在apache的access log中會看到很多如下的通路日志:
127.0.0.1 - - [05/may/2011:10:54:07 +0800] "options * http/1.0" 200 -
127.0.0.1 - - [05/may/2011:10:54:08 +0800] "options * http/1.0" 200 -
127.0.0.1 - - [05/may/2011:10:54:09 +0800] "options * http/1.0" 200 -
127.0.0.1 - - [05/may/2011:10:54:10 +0800] "options * http/1.0" 200 -
這是什麼意思呢?
apache的文檔中, 有如下的說明:
when the apache http server manages its child processes, it needs a way to wake up processes that are listening for new connections. to do this, it sends a simple http request back to itself. this request will appear in the access_log file with the remote address set to the loop-back interface (typically 127.0.0.1 or ::1 if ipv6 is configured). if you log the user-agent string (as in the combined log format), you will see the server signature followed by “(internal dummy connection)” on non-ssl servers. during certain periods you may see up to one such request for each httpd child process.
可是,為什麼要喚醒呢? 喚醒是為了做什麼呢?
在apache prefork模式下, 啟動的時候,apache就會fork出一些worker程序, 來準備接受請求, 這些worker程序,在完成準備工作以後, 就會進入block模式的監聽沉睡中, 等待請求到來而被喚醒。
另外一方面, 在prefork模式下, 當請求很多, 目前的worker程序數不夠處理的時候, 就會額外再fork一些worker程序出來, 以滿足目前的請求。
而在這些請求高峰過後, 如果額外fork出來的程序數大于了maxspareservers, apache就會告訴這些worker程序退出, 那麼問題就來了。
這些程序都在沉睡中啊, 怎麼告訴他們, 并且讓他們自我退出呢?
apache會首先發送一個退出狀态字(graceful_char !)給這些work程序:
static apr_status_t pod_signal_internal(ap_pod_t *pod)
{
apr_status_t rv;
char char_of_death = '!';
apr_size_t one = 1;
rv = apr_file_write(pod->pod_out, &char_of_death, &one);
if (rv != apr_success) {
ap_log_error(aplog_mark, aplog_warning, rv, ap_server_conf,
"write pipe_of_death");
}
return rv;
但此時, worker程序不會去讀這些狀态字, 因為他們還在沉睡。
這個時候apache就會發送一個options請求給自己, 喚醒這些沉睡的程序:
static apr_status_t dummy_connection(ap_pod_t *pod)
//...有省略
/* create the request string. we include a user-agent so that
* adminstrators can track down the cause of the odd-looking
* requests in their logs.
*/
srequest = apr_pstrcat(p, "options * http/1.0\r\nuser-agent: ",
ap_get_server_banner(),
" (internal dummy connection)\r\n\r\n", null);
這些程序在處理完目前請求以後(options請求), 就會發現, oh, 主程序讓我退出。
static void child_main(int child_num_arg)
while (!die_now && !shutdown_pending) {
//1. listen
//2. accept
//3. process request
/* check the pod and the generation number after processing a
* connection so that we'll go away if a graceful restart occurred
* while we were processing the connection or we are the lucky
* idle server process that gets to die.
if (ap_mpm_pod_check(pod) == apr_success) { /* selected as idle? */
die_now = 1;
于是, 它就做完清理工作, 然後自我消亡了~~~
原文釋出時間:2014-11-09
本文來自雲栖合作夥伴“linux中國”