理解HTTP之keep-alive


理解HTTP之keep-alive

在前面一篇文章中講了TCP的keepalive,這篇文章再講講HTTP層面keep-alive。兩種keepalive在拼寫上面就是不一樣的,只是發音一樣,於是乎大家就都迷茫了。HTTP層面的keep-alive是我們接觸比較多的,也是大家平時口頭上的"keepalive"。下面我們就來談談HTTP的keep-alive

短連接&長連接&並行連接

再說keep-alive之前,先說說HTTP的短連接&長連接。

  • 短連接

    所謂短連接,就是每次請求一個資源就建立連接,請求完成后連接立馬關閉。每次請求都經過“創建tcp連接->請求資源->響應資源->釋放連接”這樣的過程

  • 長連接

    所謂長連接(persistent connection),就是只建立一次連接,多次資源請求都復用該連接,完成后關閉。要請求一個頁面上的十張圖,只需要建立一次tcp連接,然后依次請求十張圖,等待資源響應,釋放連接。

  • 並行連接

    所謂並行連接(multiple connections),其實就是並發的短連接。

keep-alive

具體client和server要從短連接到長連接最簡單演變需要做如下改進:

  1. client發出的HTTP請求頭需要增加Connection:keep-alive字段
  2. Web-Server端要能識別Connection:keep-alive字段,並且在http的response里指定Connection:keep-alive字段,告訴client,我能提供keep-alive服務,並且"應允"client我暫時不會關閉socket連接

在HTTP/1.0里,為了實現client到web-server能支持長連接,必須在HTTP請求頭里顯示指定

Connection:keep-alive

在HTTP/1.1里,就默認是開啟了keep-alive,要關閉keep-alive需要在HTTP請求頭里顯示指定

Connection:close

現在大多數瀏覽器都默認是使用HTTP/1.1,所以keep-alive都是默認打開的。一旦client和server達成協議,那么長連接就建立好了。

接下來client就給server發送http請求,繼續上面的例子:請求十張圖片。如果每次"請求->響應"都是獨立的,那還好,10張圖片的內容都是獨立的。但是如果pipeline模式,上一個請求還沒響應,下一個請求就發出,這樣並發地發出10個請求,對於10個response client要怎么區分呢?而HTTP協議又是沒有辦法區分的,所以這種情況下必須要求server端地響應是順序的,通過Conten-Length區分每次請求,這還只是針對靜態資源,那對於動態資源無法預知頁面大小的情況呢?我還沒有深入研究,可以查看https://www.byvoid.com/blog/http-keep-alive-header

另外注意: 指定keep-alive是一種client和server端盡可能需要滿足的約定,client和server可以在任意時刻都關閉keep-alive,彼此都不應該受影響。

Nginx keepa-alive配置

具體到Nginx的HTTP層的keepalive配置有

  • keepalive_timeout
    Syntax: keepalive_timeout timeout [header_timeout];
    Default:    keepalive_timeout 75s;
    Context:    http, server, location

The first parameter sets a timeout during which a keep-alive client connection will stay open on the server side. The zero value disables keep-alive client connections. The optional second parameter sets a value in the “Keep-Alive: timeout=time” response header field. Two parameters may differ.

  • keepalive_requests
    Syntax: keepalive_requests number;
    Default:    keepalive_requests 100;
    Context:    http, server, location

Sets the maximum number of requests that can be served through one keep-alive connection. After the maximum number of requests are made, the connection is closed.

可以看看Nginx的關於 keepalive_timeout 是實現


./src/http/ngx_http_request.c static void ngx_http_finalize_connection(ngx_http_request_t *r){ ... if (!ngx_terminate && !ngx_exiting && r->keepalive && clcf->keepalive_timeout > 0) { ngx_http_set_keepalive(r); return; } ... } static void ngx_http_set_keepalive(ngx_http_request_t *r){ //如果發現是pipeline請求,判斷條件是緩存區里有N和N+1個請求同時存在 if (b->pos < b->last) { /* the pipelined request */ } // 本次請求已經結束,開始釋放request對象資源 r->keepalive = 0; ngx_http_free_request(r, 0); c->data = hc; // 如果嘗試讀取keep-alive的socket返回值不對,可能是客戶端close了。那么就關閉socket if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_close_connection(c); return; } //開始正式處理pipeline ... rev->handler = ngx_http_keepalive_handler; ... // 設置了一個定時器,觸發時間是keepalive_timeout的設置 ngx_add_timer(rev, clcf->keepalive_timeout); ... } static void ngx_http_keepalive_handler(ngx_event_t *rev){ // 發現超時則關閉socket if (rev->timedout || c->close) { ngx_http_close_connection(c); return; } // 讀取keep-alive設置從socket n = c->recv(c, b->last, size); if (n == NGX_AGAIN) { if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_close_connection(c); return; } ... } //此處尚有疑惑? ngx_reusable_connection(c, 0); c->data = ngx_http_create_request(c); // 刪除定時器 ngx_del_timer(rev); // 重新開始處理請求 rev->handler = ngx_http_process_request_line; ngx_http_process_request_line(rev); }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM