最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

nginx長(zhǎng)連接keepalive與pipeline使用及說(shuō)明

 更新時(shí)間:2025年12月22日 09:21:56   作者:ApeLife  
TCP和HTTP都支持keepalive機(jī)制,但實(shí)現(xiàn)方式不同,TCP通過(guò)自動(dòng)發(fā)送空?qǐng)?bào)文來(lái)確認(rèn)對(duì)方是否在線,而HTTP通過(guò)復(fù)用TCP連接來(lái)提高效率

tcp與http都支持keepalive機(jī)制,但兩者是不同的。先看下tcp的keepalive機(jī)制。當(dāng)客戶端與服務(wù)器建立了tcp連接后,如果客戶端一直不發(fā)送數(shù)據(jù),或者隔很長(zhǎng)時(shí)間才發(fā)送一次數(shù)據(jù)。當(dāng)連接很久沒(méi)有數(shù)據(jù)報(bào)文傳輸時(shí),服務(wù)器如何去確定對(duì)方還在線。到底是掉線了還是確實(shí)沒(méi)有數(shù)據(jù)傳輸,連接還需不需要保持,這種情況在TCP協(xié)議設(shè)計(jì)中是需要考慮的。TCP協(xié)議通過(guò)一種巧妙的方式去解決這個(gè)問(wèn)題,當(dāng)超過(guò)一段時(shí)間之后,TCP自動(dòng)發(fā)送一個(gè)數(shù)據(jù)為空的報(bào)文給對(duì)方,如果對(duì)方回應(yīng)了這個(gè)報(bào)文,說(shuō)明對(duì)方還在線,連接可以繼續(xù)保持,如果對(duì)方?jīng)]有報(bào)文返回并且重試了多次之后則認(rèn)為連接丟失,沒(méi)有必要保持連接。這個(gè)過(guò)程相當(dāng)于服務(wù)器向客戶端發(fā)送心跳包,確認(rèn)客戶端是否還在線。

而http的keepalive機(jī)制為:通??蛻舳藶g覽器要展現(xiàn)一張完整的頁(yè)面需要很多個(gè)請(qǐng)求才能完成,如圖片,js,CSS等。如果每一個(gè)HTTP請(qǐng)求都需要新建并斷開(kāi)一個(gè)TCP,這個(gè)開(kāi)銷(xiāo)是完全沒(méi)有必要的。開(kāi)啟HTTP Keep-Alive之后,能復(fù)用已有的TCP鏈接, 當(dāng)一個(gè)請(qǐng)求已經(jīng)響應(yīng)完畢,服務(wù)器端沒(méi)有立即關(guān)閉TCP連接,而是等待一段時(shí)間繼續(xù)接收瀏覽器可能發(fā)送過(guò)來(lái)的第二個(gè)請(qǐng)求,通常瀏覽器在第一個(gè)請(qǐng)求返回之后會(huì)立即發(fā)送第二個(gè)請(qǐng)求。因此在一個(gè)tcp連接上可以存在多個(gè)http請(qǐng)求,當(dāng)然這個(gè)如果客戶端一直不發(fā)送新的http請(qǐng)求,超過(guò)一段時(shí)間后,nginx服務(wù)器還是會(huì)關(guān)閉這個(gè)TCP長(zhǎng)連接。

開(kāi)啟keepalive功能,可以減少time-wait套接字的個(gè)數(shù)

一、keealive的請(qǐng)求頭部解析

在http1.0協(xié)議里,需要客戶端發(fā)送connection: keep-alive請(qǐng)求頭來(lái)實(shí)現(xiàn)與服務(wù)器之間的長(zhǎng)連接,否則長(zhǎng)連接默認(rèn)是關(guān)閉的。 http1.1默認(rèn)支持keepalive,也就是說(shuō)即使客戶端沒(méi)有發(fā)送connection:keep_alive請(qǐng)求頭部,服務(wù)器也會(huì)設(shè)置keepalive屬性,然后等待客戶端下一次請(qǐng)求。但通過(guò)請(qǐng)求頭connection: close可明確要求不進(jìn)行長(zhǎng)連接保持。先看下如何設(shè)置keepalive。

//http請(qǐng)求頭部常用頭部對(duì)應(yīng)的處理函數(shù)
ngx_http_header_t  ngx_http_headers_in[] = 
{
    { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection),ngx_http_process_connection },
};
//處理http請(qǐng)求頭部的connection字段
static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
    ngx_uint_t offset)
{
    if (ngx_strcasestrn(h->value.data, "close", 5 - 1))
	{
		//長(zhǎng)連接關(guān)閉
        r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;		

    } 
	else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) 
	{
		//保持長(zhǎng)連接
        r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE;
    }

    return NGX_OK;
}

在解析http頭部的connection字段后,將會(huì)設(shè)置TCP的連接類(lèi)型,是打開(kāi)長(zhǎng)連接還是關(guān)閉長(zhǎng)連接。然后會(huì)設(shè)置到請(qǐng)求對(duì)象的keepalive中。對(duì)于keepalive只用于服務(wù)器與客戶端保持TCP長(zhǎng)連接,而nginx內(nèi)部操作,例如內(nèi)部跳轉(zhuǎn), 命名location跳轉(zhuǎn)、子請(qǐng)求等是不需要用到keepalive的。

//調(diào)用各個(gè)http模塊協(xié)同處理這個(gè)請(qǐng)求
void ngx_http_handler(ngx_http_request_t *r)
{
	//不需要進(jìn)行內(nèi)部跳轉(zhuǎn)。keepalive機(jī)制是在客戶端和nginx服務(wù)器之間才需要關(guān)注。對(duì)于內(nèi)部跳轉(zhuǎn)則不會(huì)用到
	//keepalive機(jī)制
    if (!r->internal) 	
	{
        switch (r->headers_in.connection_type) 
		{
	        case 0:
	            r->keepalive = (r->http_version > NGX_HTTP_VERSION_10);//http1.1版本默認(rèn)開(kāi)啟keepalive
	            break;
	        case NGX_HTTP_CONNECTION_CLOSE:
	            r->keepalive = 0;					//關(guān)閉長(zhǎng)連接
	            break;
	        case NGX_HTTP_CONNECTION_KEEP_ALIVE: 
	            r->keepalive = 1;                   //打開(kāi)長(zhǎng)連接
	            break;
        }
	}
}

二、keepalive的設(shè)置

當(dāng)一個(gè)http請(qǐng)求完成后, 這個(gè)時(shí)候引用計(jì)數(shù)為0了,會(huì)釋放這個(gè)http請(qǐng)求,但到底要不要釋放tcp連接,是由keepalive機(jī)制與延遲關(guān)閉機(jī)制決定的。keepalive相比延遲關(guān)閉,優(yōu)先級(jí)更高。來(lái)看下ngx_http_finalize_connection函數(shù)的實(shí)現(xiàn)。

//釋放http請(qǐng)求與連接
static void ngx_http_finalize_connection(ngx_http_request_t *r)
{
	//執(zhí)行到這里,引用計(jì)數(shù)為1,則要準(zhǔn)備結(jié)束請(qǐng)求了
	//keepalive為1表示請(qǐng)求需要釋放,但tcp連接還是用復(fù)用的
    if (!ngx_terminate
         && !ngx_exiting
         && r->keepalive
         && clcf->keepalive_timeout > 0)
    {
        ngx_http_set_keepalive(r);
        return;
    }
}

keepalive_timeout可以在nginx.conf配置文件中,通過(guò)keepalive_timeout指令設(shè)置,默認(rèn)情況下超時(shí)時(shí)間就是75秒。如果超過(guò)這個(gè)時(shí)間都還沒(méi)有收到來(lái)自客戶端新的http請(qǐng)求,則會(huì)關(guān)閉這個(gè)tcp連接,keepalive功能也就結(jié)束了。ngx_http_set_keepalive函數(shù)則是正式開(kāi)始keepalive的處理,函數(shù)有點(diǎn)長(zhǎng),實(shí)現(xiàn)了pipeline長(zhǎng)連接與普通長(zhǎng)連接。先來(lái)看下pipeline的實(shí)現(xiàn)。

三、pipeline處理

那么什么是pipeline呢?pipeline其實(shí)就是流水線作業(yè),它可以看作為keepalive的一種升華,因?yàn)閜ipeline也是基于長(zhǎng)連接的,目的就是利用一個(gè)連接做多次請(qǐng)求。如果客戶端要提交多個(gè)請(qǐng)求,對(duì)于keepalive來(lái)說(shuō),那么第二個(gè)請(qǐng)求,必須要等到第一個(gè)請(qǐng)求的響應(yīng)接收完全后,才能發(fā)起,這和TCP的停止等待協(xié)議是一樣的,得到兩個(gè)響應(yīng)的時(shí)間至少為2*RTT。而對(duì)pipeline來(lái)說(shuō),客戶端不必等到第一個(gè)請(qǐng)求處理完后,就可以馬上發(fā)起第二個(gè)請(qǐng)求。得到兩個(gè)響應(yīng)的時(shí)間可能能夠達(dá)到1*RTT。nginx是直接支持pipeline的,但是,nginx對(duì)pipeline中的多個(gè)請(qǐng)求的處理卻不是并行的,依然是一個(gè)請(qǐng)求接一個(gè)請(qǐng)求的處理,只是在處理第一個(gè)請(qǐng)求的時(shí)候,客戶端就可以發(fā)起第二個(gè)請(qǐng)求。這樣,nginx利用pipeline減少了處理完一個(gè)請(qǐng)求后,等待第二個(gè)請(qǐng)求的請(qǐng)求行與請(qǐng)求頭部的時(shí)間。其實(shí)nginx的做法很簡(jiǎn)單,前面說(shuō)到,nginx在讀取數(shù)據(jù)時(shí),會(huì)將讀取的數(shù)據(jù)放到一個(gè)buffer里面,所以,如果nginx在處理完前一個(gè)請(qǐng)求后,如果發(fā)現(xiàn)buffer里面還有數(shù)據(jù),就認(rèn)為剩下的數(shù)據(jù)是下一個(gè)請(qǐng)求的開(kāi)始,然后接下來(lái)處理下一個(gè)請(qǐng)求,否則就設(shè)置keepalive。

來(lái)看下nginx服務(wù)器是如何處理pipeline的?

//設(shè)置keepalive過(guò)程
static void ngx_http_set_keepalive(ngx_http_request_t *r)
{
	//在接收到來(lái)自客戶端的連接請(qǐng)求時(shí),同時(shí)也接收到了同一個(gè)tcp連接上的第2個(gè)http請(qǐng)求頭部。
	//因此在處理完第一個(gè)請(qǐng)求時(shí),pos不等于last,說(shuō)明接收到了第二個(gè)http請(qǐng)求頭部,接下來(lái)要立馬處理第二個(gè)請(qǐng)求
    if (b->pos < b->last) 
	{
		//在接收來(lái)自客戶端的請(qǐng)求行、或者請(qǐng)求頭部時(shí)。如果連接對(duì)象的buffer緩沖區(qū)不能夠存放所有的請(qǐng)求行,請(qǐng)求頭。
		//則http請(qǐng)求對(duì)象自己會(huì)開(kāi)辟新的空間。因此在請(qǐng)求結(jié)束時(shí),需要把請(qǐng)求對(duì)象開(kāi)辟的空間加入到空閑表中。
		//這樣在這個(gè)連接上有新的http請(qǐng)求到來(lái)時(shí),可以復(fù)用上一個(gè)請(qǐng)求對(duì)象開(kāi)辟的空間
        if (b != c->buffer) 
		{
            if (hc->free == NULL)
			{
                hc->free = ngx_palloc(c->pool, cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *));
            }
			
			//將在用表移動(dòng)到空閑表
            for (i = 0; i < hc->nbusy - 1; i++)
			{
                f = hc->busy[i];
                hc->free[hc->nfree++] = f;
                f->pos = f->start;
                f->last = f->start;
            }

            hc->busy[0] = b;
            hc->nbusy = 1;
        }
    }
}

(1) nginx服務(wù)器是怎么知道需要進(jìn)行pipeline處理呢? 條件就是這個(gè)b->pos < b->last。 多個(gè)http請(qǐng)求可以復(fù)用同一個(gè)tcp連接,客戶端瀏覽器在發(fā)出第一個(gè)http請(qǐng)求時(shí),可以不需要等待收到服務(wù)器的響應(yīng),可以立馬發(fā)出第二個(gè)http請(qǐng)求。在這種請(qǐng)求下,nginx服務(wù)器收到第一個(gè)http請(qǐng)求時(shí),是有可能也接收到了第二個(gè)http請(qǐng)求的頭部信息,并保存到http請(qǐng)求對(duì)象的header_in緩沖區(qū)中??聪逻@個(gè)接收過(guò)程, 函數(shù)只負(fù)責(zé)從內(nèi)核讀取數(shù)據(jù)到緩沖區(qū),并沒(méi)有限制只讀取第一個(gè)http請(qǐng)求的數(shù)據(jù),如果有第二個(gè)http請(qǐng)求,也會(huì)把第二個(gè)http請(qǐng)求頭部也讀取到緩沖區(qū)。

static ssize_t ngx_http_read_request_header(ngx_http_request_t *r)
{
	//事件就緒,也就是從epoll_wait中返回后,從內(nèi)核緩沖區(qū)中讀取內(nèi)容到應(yīng)用層緩沖區(qū)header_in
    if (rev->ready) 
	{
		//ngx_unix_recv
        n = c->recv(c, r->header_in->last, r->header_in->end - r->header_in->last);  
    } 
}

那這個(gè)b != c->buffer又怎么理解呢? 默認(rèn)情況下http請(qǐng)求結(jié)構(gòu)的header_in緩沖區(qū)是等于連接對(duì)象的buffer緩沖區(qū)的。 看下面這個(gè)函數(shù)就知道了。剛建立http請(qǐng)求時(shí),兩個(gè)緩沖區(qū)都指向同一個(gè)內(nèi)存空間。

//首次建立tcp連接后,讀事件的回調(diào),用于創(chuàng)建一個(gè)ngx_http_request_t對(duì)象
static void ngx_http_init_request(ngx_event_t *rev)
{	
	//剛建立的請(qǐng)求,默認(rèn)情況下這兩個(gè)緩沖區(qū)是相等的
    if (r->header_in == NULL) 
	{
        r->header_in = c->buffer;
    }
}

什么情況下http請(qǐng)求結(jié)構(gòu)的header_in緩沖區(qū)會(huì)不等于連接對(duì)象的buffer緩沖區(qū)呢? nginx服務(wù)器在接收到來(lái)自客戶端的http請(qǐng)求行或者請(qǐng)求頭部時(shí),如果接受緩沖區(qū)不能夠存放請(qǐng)求行或者請(qǐng)求頭時(shí),是會(huì)開(kāi)辟一個(gè)新的緩沖區(qū),并把這個(gè)緩沖區(qū)加入到在用緩沖區(qū)數(shù)組busy中。通常情況下nginx服務(wù)器的默認(rèn)緩沖區(qū)是足夠存放一個(gè)http請(qǐng)求行或者請(qǐng)求頭部的, 之所以緩沖區(qū)不夠,大部分情況下是接收到了多個(gè)http請(qǐng)求頭部。這種情況下將會(huì)執(zhí)行pipeline處理

//開(kāi)辟一個(gè)大的緩沖區(qū),并把舊緩沖區(qū)的數(shù)據(jù)拷貝到新緩沖區(qū)中
//解析請(qǐng)求行時(shí),request_line = 1, 解析請(qǐng)求頭時(shí),request_line = 0
static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, ngx_uint_t request_line)
{
	/* 檢查給該請(qǐng)求分配的請(qǐng)求頭緩沖區(qū)個(gè)數(shù)是否已經(jīng)超過(guò)限制,默認(rèn)最大個(gè)數(shù)為4個(gè) */ 
	if (hc->busy == NULL) 
	{
		hc->busy = ngx_palloc(r->connection->pool, cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *));
	}

	/* 如果還沒(méi)有達(dá)到最大分配數(shù)量,則分配一個(gè)新的大緩沖區(qū) */  
	b = ngx_create_temp_buf(r->connection->pool, cscf->large_client_header_buffers.size);

	/* 將從空閑隊(duì)列取得的或者新分配的緩沖區(qū)加入已使用隊(duì)列 */  
    hc->busy[hc->nbusy++] = b;
	
	//header_in指向這個(gè)新的緩沖區(qū), 連接對(duì)象的緩沖區(qū)仍然為舊的緩沖區(qū),大小沒(méi)有改變
    r->header_in = b;
}

為什么要把busy這個(gè)在用緩沖區(qū)數(shù)據(jù)移動(dòng)到空閑緩沖區(qū)數(shù)組呢? 為什么不直接釋放這些空間呢? 還是因?yàn)閜ipeline的原因,因?yàn)槌水?dāng)前要結(jié)束的這個(gè)http請(qǐng)求外,緩沖區(qū)中還存放了其它的http請(qǐng)求。當(dāng)這個(gè)http請(qǐng)求結(jié)束時(shí),可以立即處理剩余的http請(qǐng)求。而如果不是pipeline,則會(huì)關(guān)閉這些緩沖區(qū)的, 這種情況下是一個(gè)普通的TCP長(zhǎng)連接,客戶端什么時(shí)候會(huì)再次發(fā)送http請(qǐng)求,以及是否真的還會(huì)在發(fā)送http請(qǐng)求是不可知的, nginx將會(huì)釋放這些資源。

(2)接下來(lái)要釋放一個(gè)http請(qǐng)求了,但請(qǐng)求本身這個(gè)對(duì)象沒(méi)有釋放, 這樣在這個(gè)tcp連接上的已經(jīng)接收到的其它請(qǐng)求可以復(fù)用這個(gè)http請(qǐng)求對(duì)象。同時(shí)也會(huì)設(shè)置keepalive的超時(shí)時(shí)間,超過(guò)這個(gè)時(shí)間后會(huì)真正關(guān)閉這個(gè)tcp連接。

//設(shè)置keepalive過(guò)程
static void ngx_http_set_keepalive(ngx_http_request_t *r)
{
	//釋放請(qǐng)求的內(nèi)容空間
    ngx_http_free_request(r, 0);
	//將讀事件注冊(cè)到紅黑樹(shù)實(shí)現(xiàn)的定時(shí)器中,超時(shí)時(shí)間由keepalive_timeout命令設(shè)置,默認(rèn)為75秒。
	//如果超時(shí)時(shí)間到后都還沒(méi)有再收到來(lái)自客戶端的http請(qǐng)求,則會(huì)關(guān)閉連接。
    ngx_add_timer(rev, clcf->keepalive_timeout);
    ngx_handle_read_event(rev, 0);
	//接收來(lái)自客戶端請(qǐng)求時(shí),還不需要向客戶端寫(xiě)入數(shù)據(jù),因此把寫(xiě)回調(diào)設(shè)置為不做任何事情
    wev = c->write;
    wev->handler = ngx_http_empty_handler;
}

(3)在pipeline這種情況下,當(dāng)前http請(qǐng)求已經(jīng)結(jié)束了。那nginx如何處理這個(gè)tcp連接上的其它http請(qǐng)求呢? nginx服務(wù)器將會(huì)設(shè)置讀事件ngx_event_t的接收回調(diào)handler為:ngx_http_init_request,并立馬把讀事件加入到post隊(duì)列中。因此這個(gè)讀事件就會(huì)被立即調(diào)用,從而開(kāi)始處理這個(gè)tcp連接上的其它http請(qǐng)求。

static void ngx_http_set_keepalive(ngx_http_request_t *r)
{
	//該請(qǐng)求結(jié)束了,設(shè)置接收回調(diào)為ngx_http_init_request。在這個(gè)tcp連接上的下一個(gè)請(qǐng)求到來(lái)時(shí),
	//重新開(kāi)始對(duì)一個(gè)新請(qǐng)求進(jìn)行處理
    if (b->pos < b->last) 
	{
		//設(shè)置為串行請(qǐng)求
        hc->pipeline = 1;
		//設(shè)置讀事件的回調(diào),并加入到post事件隊(duì)列
        rev->handler = ngx_http_init_request;
        ngx_post_event(rev, &ngx_posted_events);
        return;
    }
}

看下ngx_http_init_request這個(gè)函數(shù)怎么在這個(gè)tcp連接上重新創(chuàng)建一個(gè)http請(qǐng)求。對(duì)于pipeline,是不會(huì)創(chuàng)建一個(gè)新的http請(qǐng)求的,而是復(fù)用已經(jīng)結(jié)束的http請(qǐng)求。也可以看出不管是在這個(gè)tcp連接上新建立的http請(qǐng)求,還是當(dāng)前請(qǐng)求結(jié)束后重新建立了一個(gè)新的http請(qǐng)求,都會(huì)調(diào)用ngx_http_init_request這個(gè)函數(shù)進(jìn)行處理。

static void ngx_http_init_request(ngx_event_t *rev)
{
    r = hc->request;
    if (r) 
	{
        ngx_memzero(r, sizeof(ngx_http_request_t));
		//串行請(qǐng)求時(shí)值為1,表示舊請(qǐng)求結(jié)束后,內(nèi)部資源已經(jīng)釋放了,但請(qǐng)求本身沒(méi)有釋放。
		//這樣的話,在這個(gè)tcp連接上的新請(qǐng)求可以使用舊請(qǐng)求的對(duì)象。
		//配和ngx_http_set_keepalive函數(shù)就理解這部分的實(shí)現(xiàn)了
        r->pipeline = hc->pipeline;

		//串行請(qǐng)求時(shí),在用緩沖區(qū)加入到了空閑緩沖區(qū)數(shù)組中。配和ngx_http_set_keepalive函數(shù)幫助理解
        if (hc->nbusy) 
		{
            r->header_in = hc->busy[0];
        }
    } 
}

需要注意的是pipeline只支持冪等請(qǐng)求,也就是并發(fā)請(qǐng)求之間沒(méi)有依賴關(guān)系,不管執(zhí)行多少次結(jié)果都應(yīng)該是一樣的。例如在第二個(gè)請(qǐng)求需要等待第一個(gè)請(qǐng)求的響應(yīng)從而決定一些行為時(shí),這種場(chǎng)景下就不能使用pipeline。第一個(gè)請(qǐng)求添加用戶信息,第二個(gè)請(qǐng)求更新用戶信息,這種場(chǎng)景下就不能使用pipeline。當(dāng)然這需要由客戶端自己來(lái)保證,并發(fā)發(fā)送多個(gè)冪等性的請(qǐng)求。

到此對(duì)pipeline這種長(zhǎng)連接的處理過(guò)程已經(jīng)分析完成了,下面將分析下非pipeline情況下的長(zhǎng)連接的處理過(guò)程。暫且稱(chēng)非pipeline的長(zhǎng)連接為普通長(zhǎng)連接吧!

四、普通長(zhǎng)連接處理

如果不是pipeline這種串行請(qǐng)求,因此會(huì)盡可能的釋放該請(qǐng)求空間。因?yàn)檫@個(gè)tcp連接上什么時(shí)候會(huì)有客戶端發(fā)來(lái)新的http請(qǐng)求,以及是否真的會(huì)有新的http請(qǐng)求是不確定的。nginx秉承一個(gè)能盡量減少資源占用就減少資源的原則,會(huì)把這個(gè)http請(qǐng)求內(nèi)部開(kāi)辟的資源給釋放,同時(shí)也把請(qǐng)求對(duì)象本身也真正的釋放, 但tcp連接還是沒(méi)有關(guān)閉,等超時(shí)沒(méi)有收到來(lái)自客戶端的http請(qǐng)求時(shí)在關(guān)閉。以此同時(shí)將會(huì)設(shè)置讀事件ngx_event_t的接收回調(diào)handler為:ngx_http_keepalive_handler,用來(lái)處理在這個(gè)tcp連接上的其它http請(qǐng)求(這里不像pipeline, 當(dāng)前http請(qǐng)求結(jié)束了,但此時(shí)這個(gè)tcp連接上并沒(méi)有其它的http請(qǐng)求存在)。

static void ngx_http_set_keepalive(ngx_http_request_t *r)
{
	//釋放資源
	if (hc->busy) 
	{
        for (i = 0; i < hc->nbusy; i++) 
		{
            ngx_pfree(c->pool, hc->busy[i]->start);
            hc->busy[i] = NULL;
        }
    }
	
	//設(shè)置讀事件回調(diào),用于處理來(lái)自客戶端的新的http請(qǐng)求
    rev->handler = ngx_http_keepalive_handler;
}

現(xiàn)在來(lái)看是ngx_http_keepalive_handler這個(gè)函數(shù)的處理過(guò)程。函數(shù)內(nèi)部會(huì)開(kāi)辟一些必要的緩沖區(qū)外,最終還是回調(diào)用ngx_http_init_request這個(gè)函數(shù)重新開(kāi)始一個(gè)新的http請(qǐng)求。

//http請(qǐng)求關(guān)閉后,tcp連接并沒(méi)有關(guān)閉。這個(gè)函數(shù)用于在這個(gè)tcp連接上接收新的http請(qǐng)求
static void ngx_http_keepalive_handler(ngx_event_t *rev)
{
	//開(kāi)辟接收請(qǐng)求行、請(qǐng)求頭緩沖區(qū)。因?yàn)榉莗ipeline情況下,釋放之前的一個(gè)請(qǐng)求時(shí),
	//也把連接對(duì)象的buffer緩沖區(qū)也給釋放了。因此新的請(qǐng)求到來(lái)時(shí),需要重新開(kāi)辟空間
	b->pos = ngx_palloc(c->pool, size);

	//調(diào)用這個(gè)函數(shù),重新開(kāi)始一個(gè)新的http請(qǐng)求處理
    ngx_http_init_request(rev);
}

可以看出,在同一個(gè)tcp連接下,不管是第一次建立的請(qǐng)求,還是之后重新建立的請(qǐng)求,最終都會(huì)調(diào)用ngx_http_init_request這個(gè)函數(shù)。由這個(gè)函數(shù)負(fù)責(zé)對(duì)請(qǐng)求的初始化操作。由此也可以知道,多個(gè)http請(qǐng)求是可以復(fù)用同一個(gè)tcp連接的。沒(méi)有必要客戶端發(fā)起一個(gè)http請(qǐng)求就建立一個(gè)tcp連接,太浪費(fèi)資源了。到此keepalive機(jī)制與pipeline已經(jīng)分析完成了, 因?yàn)閗eepalive機(jī)制和在同一個(gè)tcp連接上重新建立一個(gè)新的http請(qǐng)求有關(guān),也與關(guān)閉一個(gè)http請(qǐng)求有關(guān),跨度比較大,看了也比較混亂。如果對(duì)http請(qǐng)求初始化過(guò)程還不是很清楚,可以參考前面的文章。下一篇文章將會(huì)對(duì)nginx的延遲關(guān)閉功能進(jìn)行分析。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • nginx日志格式分析以及修改詳解

    nginx日志格式分析以及修改詳解

    Nginx日志對(duì)于統(tǒng)計(jì)、系統(tǒng)服務(wù)排錯(cuò)很有用,下面這篇文章主要給大家介紹了關(guān)于nginx日志格式分析以及修改的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • filebeat同時(shí)收集錯(cuò)誤日志與普通日志并存詳解

    filebeat同時(shí)收集錯(cuò)誤日志與普通日志并存詳解

    這篇文章主要為大家介紹了filebeat同時(shí)收集錯(cuò)誤日志與普通日志并存詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • nginx常用配置conf的示例代碼詳解

    nginx常用配置conf的示例代碼詳解

    這篇文章主要介紹了nginx常用配置conf,包括配置vue項(xiàng)目,配置接口代理的代碼詳解,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • ubuntu16.04下徹底卸載nginx的相關(guān)命令

    ubuntu16.04下徹底卸載nginx的相關(guān)命令

    nginx是一款自由的、開(kāi)源的、高性能的HTTP服務(wù)器和反向代理服務(wù)器;這篇文章主要介紹了ubuntu16.04下徹底卸載nginx的相關(guān)命令,需要的朋友可以參考下
    2018-12-12
  • 前端服務(wù)器部署Nginx?+docker?+?ubuntu的完整過(guò)程

    前端服務(wù)器部署Nginx?+docker?+?ubuntu的完整過(guò)程

    Docker是一個(gè)開(kāi)源的容器化平臺(tái),可以讓你快速構(gòu)建、測(cè)試和部署應(yīng)用程序,Nginx是一個(gè)高性能的Web服務(wù)器和反向代理服務(wù)器,常用于部署靜態(tài)網(wǎng)站、負(fù)載均衡等場(chǎng)景,這篇文章主要介紹了前端服務(wù)器部署Nginx?+docker?+?ubuntu的完整過(guò)程,需要的朋友可以參考下
    2025-11-11
  • 解讀Nginx變量字段大全

    解讀Nginx變量字段大全

    這篇文章主要介紹了Nginx變量字段,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-07-07
  • Nginx超時(shí)時(shí)間的配置說(shuō)明

    Nginx超時(shí)時(shí)間的配置說(shuō)明

    Nginx超時(shí)時(shí)間非常重要,因?yàn)樗鼘⒅苯佑绊懢W(wǎng)站的響應(yīng)速度和用戶體驗(yàn),本文主要介紹了Nginx超時(shí)時(shí)間的配置說(shuō)明,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-07-07
  • Nginx try_files 指令常見(jiàn)用法示例

    Nginx try_files 指令常見(jiàn)用法示例

    try_files是Nginx用于按順序檢查文件是否存在并返回第一個(gè)找到的文件,本文給大家介紹Nginx try_files 指令常見(jiàn)用法示例,感興趣的朋友跟隨小編一起看看吧
    2026-05-05
  • Linux下Nginx安裝教程

    Linux下Nginx安裝教程

    這篇文章主要為大家詳細(xì)介紹了Linux中Nginx的安裝教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Nginx服務(wù)器如何設(shè)置url鏈接

    Nginx服務(wù)器如何設(shè)置url鏈接

    這篇文章主要介紹了Nginx服務(wù)器如何設(shè)置url鏈接,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10

最新評(píng)論

贵溪市| 喀喇沁旗| 二手房| 乌审旗| 台北市| 长汀县| 庄浪县| 旬阳县| 吉木乃县| 津南区| 赤城县| 江孜县| 金堂县| 横山县| 黄大仙区| 丰原市| 绥化市| 赣州市| 延寿县| 左云县| 新化县| 湄潭县| 泾阳县| 新津县| 金阳县| 教育| 嵊州市| 武冈市| 广汉市| 新乡县| 红桥区| 手游| 嵊州市| 绥化市| 太康县| 湖北省| 长顺县| 全南县| 厦门市| 德化县| 达孜县|