1
2
3
4
5
6
4
58 11121314 15161718192021 r)
{ |
..... ....................................
switch
(r->headers_in .connection_type) {
case
0:
r->keepalive = (r->http_version > NGX_HTTP_VERSION_10);
<p><code> break ;
//如果指定connection頭為close則不需要keepalive
break ;
case NGX_HTTP_CONNECTION_KEEP_ALIVE:
r->keepalive = 1;
break ;
}
..................................
}
然後我們知道keepalive也就是當前的http request執行完畢後並不會直接關閉當前的連接,因此nginx的keepalive的相關處理也就是清理request的函數中。 nginx清理requst的函數是ngx_http_finalize_request,這個函數中會呼叫ngx_http_finalize_connection來釋放連接,而keepalive的相關判斷就在這個函數中。
1
2
3
4
5
6
4
58 11121314 15161718192021222
ngx_http_finalize_connection(ngx_http_request_t *r)
| {
ngx_http_core_loc_conf_t *clcf;
..................... ................................................ //可以看到如果設定了keepalive,且timeout大於0,就進入keepalive的處理。
if(!ngx_terminate
&& r->keepalive
&&Dhcf-keep {
ngx_http_set_keepalive(r);
}
else if
(r->lingering_close && clcf->lingering_timeout > 0) {
_
return ;
}
ngx_http_close_request(r, 0);
}
}
}
]
透過上面我們能看到keepalive是透過ngx_http_set_keepalive來設定的,接下來我們就來詳細的看這個函數。 在這個函數裡面會順帶處理pipeline的請求,因此我們一併來看,首先nginx是如何區分pipeline請求的呢,它會假設如果從客戶端讀取的數據多包含了一些數據,也就是解析完目前的request之後,還有一部分數據,這時,就認為是pipeline請求。 還有一個很重要的地方就是http_connection,我們在前面的blog知道,如果需要alloc large header時候,會先從hc->free裡面取,如果沒有的話,會新建,然後交給hc->busy去管理。而這個buf,就會在這裡被重用,因為large buf的話,需要重新alloc第二次,如果這裡buf有重用的話,減少一次分配。
1
2
3
4
5
6
4
58 11121314 151617181920212222233 7
28
29
30
31 32
33
34
35
36
37
38 hc = r->http_connection;
b = r->header_in;
//一般情況下,當解析完header_in之後,pos會設定為last。也就是讀取到的資料剛好是一個完整的http請求.當pos小於last,則表示可能是pipeline請求。
if(b->pos last) { |
if (b != c-> buffer) {
/*
我the previous
* request processing then we do not use c->buffer for* request processing then we do not use c->buffer for
* the pipelined request (see ngx_http_init_request()).
*
<p><code> * Now we would move the large header buffers to the free list.
<p><code> */
<p><code> cscf = ngx_http_get_module_srv_conf(r, if(hc-> free == NULL) {
//可以看到是large_client_headers的數量
<p><code> cscf->large_client_header_buffers.num *
sizeof (ngx_buf_t *));
{
<p><code> ngx_http_close_request(r, 0);ngx_http_close_request(r, 0);
return ; <p><code> }
//然後清除目前的request (i = 0; i nbusy - 1; i++) {
f = hc->busy[i];
hc->mm f->pos = f->start;
<p><code> f->last = f->start; //保存目前的header_in buf,以便與下次給free使用。
hc->busy[0] = b;
}
}
} 然後接下來這部分就是free request,並設定keepalive 定時器.
1 8 9 1011 12 13
| 14 15
ngx_http_free_request(r, 0);
c->data = hc;
//設定定時器
//然後設定可讀事件
if
(ngx_handle_read_event(rev, 0) != NGX_OK) {
return
;
|
}
wev = c->write;
wev->handler = ngx_http_empty_handler;
的部分。
1 2 3
4 5
6 4 58 11 1213 14 15
if(b->pos last) { _N TP, c->
log ,
0, "pipelined request"
);
#if (NGX_STAT_STUB)
|
_fetch_add(ngx_stat_reading,
1);
#endif//設定標記。
hc->pipeline = 1;
"reading client pipelined request line";
//然後丟進post queue,繼續處理.
.
ngx_post_event(rev , &ngx_posted_events);
return
| ;
到達下面,則表示不是pipeline的請求,因此就開始對request, http_connection 進行清理工作。
1
2
3
4
5
6
4
58 11121314 151617181920212222233 7
28
29
30
if
(ngx_pfree(c->pool, r) == NGX_OK) {
| }
b = c->buffer;
if (ngx_pfree(c->pool, b->start) == NGX_ * the special note for ngx_http_keepalive_handler() that
* c->buffer
b->pos = NULL;
}
else {
b->pos = b->start; start>
}
. .................................................. ..................
if (hc->busy) {
hc->nbusy; i++) {
ngx_pfree(c->pool,
hc->busy[i] = NULL;
}
hc->
設定keepalive的handler。
12 3 4 5 //後面會詳細分析這個函數 rev->handler = ngx_http_keepalive_handler;
if (weal_wid) (Wavw)_o_af;
if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) {
ngx_http_close_connection(c); return ; |
}
最後是對tcp push的處理,這裡暫時我就不介紹了,接下來我會有專門一篇blog來介紹nginx對tcp push的操作。 然後我們來看ngx_http_keepalive_handler函數,這個函數是處理keepalive連接,當在連接上再次有可讀的事件的時候,就會調用這個handler。 這個handler比較簡單,就是建立新的buf,然後重新開始一個http request的執行(呼叫ngx_http_init_request)。
1
2
3
4
5
6
4
58 11121314 15161718192021 size = b->end - b-> start;
|
if (b->pos == NULL) {
* The c->buffer's memory was freed by ngx_http_set_keepalive().
* However, the c->buffer->start and c->buffer->end were not changed
*/ //重新分配buf
b->pos = ngx_palloc(c->pool, size); (b->pos == NULL) {
ngx_http_close_connection(c);
return ;
}
b->start = b->pos;
b-> last = b->pos;
b->end = b->pos + size;
然後嘗試讀取數據,如果沒有可讀數據,則會再次加入可讀事件
1 23 4
n = c->recv(c, b->last, size);
c->log_error = NGX_ERROR_INFO;
if if (ngx_handle_read_event(rev, 0) != NGX_OK) {
|
ngx_http_close_connection(c); }
return;
}
最後如果讀取了數據,則進入request的處理。
|
1
ngx_http_init_request(rev); ngx_http_init_request(rev);
最後我們再來看ngx_http_init_request函數,這次主要來看當時pipeline請求的時候,nginx是如何來重複使用request的。 這裡要注意hc->busy[0],前面我們知道,如果是pipeline請求,我們會保存前面沒有解析完畢的request header_in,這是因為我們可能已經讀取了pipeline請求的第二個請求的一些頭。
1
2
3
4
5
6
4
58 11121314 1516171819202122
//取得request,這裡我們知道,在pipeline請求中,我們會保存前一個request.
r = hc->request;
| request.
ngx_memzero(r,
sizeof (ngx_http_request_t));
r->p if(hc->nbusy) {
//則儲存這個header_in,然後下面直接解析。
r->header_in = hc->busy[0];
}
else {
r = ngx_pcalloc(c->pool,
sizeof (ngx_http_request_t));
ngx_http_close_connection(c);
}
hc- = r; //保存請求
c->data = r;
從上面的程式碼,然後再結合我前一篇blog,我們就知道large header主要是針對pipeline的了,因為在pipeline中,前一個request如果多讀了下一個request的一些頭的話,這樣子下次解析的時候就有可能會超過原本分配的client_header_buffer_size,此時,我們就需要重新分配一個header,也就是large header了,所以這裡httpconnection主要就是針對pipeline的情況,而keepalive的連接並不是pipeline的請求的話,為了節省內存,就把前一個request釋放掉了.
以上就介紹了nginx對keepalive和pipeline請求處理分析,包括了方面的內容,希望對PHP教程有興趣的朋友有所幫助。
|
|
|
|
|