Nginx篇05-http长连接和keeplive
nginx中http模塊使用http長連接的相關配置(主要是keepalive指令)和http長連接的原理解釋。
1、http長連接
1.1 預備知識
連接管理是一個 HTTP 的關鍵話題:打開和保持連接在很大程度上影響著網(wǎng)站和 Web 應用程序的性能。在 HTTP/1.x 里有多種模型:短連接, 長連接, 和 HTTP 流水線。在解釋這三種模型之前,我們需要先明確一些前提知識:
- HTTP是屬于應用層(七層)的協(xié)議,同時它的傳輸層(四層)使用的是TCP協(xié)議,那么也就是說,HTTP的長連接和短連接,其本質(zhì)就是TCP的長連接和短連接;
- HTTP是一個無狀態(tài)的面向連接的協(xié)議(使用TCP,面向連接、可靠傳輸),指的是協(xié)議對于事務處理沒有記憶能力,服務器不知道客戶端是什么狀態(tài),無狀態(tài)不代表HTTP不能保持TCP連接,更不能代表HTTP使用的是UDP協(xié)議(無連接);
- TCP建立連接和斷開連接是需要三握四揮的,由于這個屬于計算機網(wǎng)絡基本知識,所以原理這里不再贅述;
接下來我們開始解釋。
1.2 HTTP短連接模型
在早期,HTTP 使用一個簡單的模型來處理這樣的連接。這些連接的生命周期是短暫的:每發(fā)起一個請求時都會創(chuàng)建一個新的連接,并在收到應答時立即關閉。這就是類似上面說的三次握手,在互聯(lián)網(wǎng)發(fā)展的早期一個網(wǎng)頁的資源并沒有現(xiàn)在這么多,很多可能只是一個簡單的靜態(tài)頁面而已,所以這樣的模型顯然很OK。客戶端獲取完所需資源之后,就斷開連接,不再占用服務器的資源。
套用TCP連接的三握四揮的模型來舉例:
三次握手:
A→B:今晚下班一起吃飯嗎?
B→A:好的,今晚下班一起吃飯。
A→B:好的,我知道你答應我今晚下班一起吃飯的邀請了。
然后開始去吃飯,吃完飯到了兩個人需要各自回家的時候:
四次揮手:
A→B:我吃完飯準備走了
B→A:等一下,我快吃完了
B→A:好了,我吃完了可以走了
A→B:好的,我知道你吃完了我們可以走了
然后兩人吃完飯就各回各家了
HTTP 短連接模型是最早期的模型,也是 HTTP/1.0 的默認模型。每一個 HTTP 請求都由它自己獨立的連接完成;這意味著發(fā)起每一個 HTTP 請求之前都會有一次 TCP 握手,而且是連續(xù)不斷的。實際上,TCP 協(xié)議握手本身就是耗費時間的,所以 TCP 可以保持更多的熱連接來適應負載。短連接破壞了 TCP 具備的能力,新的冷連接降低了其性能。
在 HTTP/1.0 中如果沒有指定 Connection協(xié)議頭,或者是值被設置為 close就會啟用短連接模型,要在 HTTP/1.0 中啟用長連接模型,需要在協(xié)議頭中指定Connection: Keep-Alive ,不過并不建議這樣操作。
而在 HTTP/1.1 中,默認使用長連接模型,只有當 Connection被設置為 close 時才會用到這個短連接模型,協(xié)議頭都不用再去聲明它(但是一般還是會把它加上,以防萬一因為某種原因要退回到 HTTP/1.0 )。
1.3 HTTP長連接模型
后來,網(wǎng)頁需要請求的資源越來越多,短連接模型顯然已經(jīng)十分吃力了。因為短連接有兩個比較大的問題:創(chuàng)建新連接耗費的時間尤為明顯(三次握手很耗費時間),另外 TCP 連接的性能只有在該連接被使用一段時間后(熱連接)才能得到改善。因此在HTTP/1.1中引入了長連接模型和流水線模型。
在 HTTP/1.1 之前,長連接也被稱為keep-alive 連接。
一個長連接會保持一段時間,重復用于發(fā)送一系列請求,節(jié)省了新建 TCP 連接握手的時間,還可以利用 TCP 的性能增強能力。當然這個連接也不會一直保留著:連接在空閑一段時間后會被關閉(服務器可以使用 Keep-Alive 協(xié)議頭來指定一個最小的連接保持時間)。
套用上面的例子來進一步解釋:
三次握手:
A→B:今晚下班一起吃飯嗎?
B→A:好的,今晚下班一起吃飯。
A→B:好的,我知道你答應我今晚下班一起吃飯的邀請了。
然后開始去吃飯,但是這時吃完飯就不是馬上四次揮手斷開連接,AB兩人還順便去逛街、看電影(相當于省去了三次握手使用已建立的連接來傳輸多個資源)
此處省略四次揮手
最后兩人就各回各家了
長連接也還是有缺點的;也就是前面提到的資源占用問題,就算是在空閑狀態(tài),它還是會消耗服務器資源,也更容易被DDoS攻擊。本質(zhì)上長連接是因為不斷地三次握手建立連接消耗的資源要大于維持連接所需要的資源才使用的,如果服務器處于高負載時段或者被DDoS,可以使用非長連接,即盡快關閉那些空閑的連接,也能對性能有所提升。
1.4 HTTP流水線模型
流水線模型的實現(xiàn)要復雜很多,而已效果也并不是特別好,主要還要考慮到各種兼容性,所以默認是不啟用這個流水線模型的,而在HTTP/2中,流水線已經(jīng)被更好的算法給代替,如multiplexing。
默認情況下,HTTP 請求是按順序發(fā)出的。**下一個請求只有在當前請求收到應答過后才會被發(fā)出。**由于會受到網(wǎng)絡延遲和帶寬的限制,在下一個請求被發(fā)送到服務器之前,可能需要等待很長時間。**流水線是在同一條長連接上發(fā)出連續(xù)的請求,而不用等待應答返回。這樣可以避免連接延遲。**理論上講,性能還會因為兩個 HTTP 請求有可能被打包到一個 TCP 消息包中而得到提升。就算 HTTP 請求不斷的繼續(xù),尺寸會增加,但設置 TCP 的 MSS(Maximum Segment Size) 選項,仍然足夠包含一系列簡單的請求。
并不是所有類型的 HTTP 請求都能用到流水線:只有 idempotent方式,比如 GET、HEAD、PUT和 DELETE能夠被安全的重試:因為有故障發(fā)生時,流水線的內(nèi)容要能被輕易的重試,即出現(xiàn)了問題重試的成本要盡可能低,否則還不如使用長連接模型。
正確的實現(xiàn)流水線是復雜的:傳輸中的資源大小,多少有效的 RTT 會被用到,還有有效帶寬,流水線帶來的改善有多大的影響范圍。不知道這些的話,重要的消息可能被延遲到不重要的消息后面。這個重要性的概念甚至會演變?yōu)橛绊懙巾撁娌季?#xff01;因此 HTTP 流水線在大多數(shù)情況下帶來的改善并不明顯。此外,流水線受制于 HOL 問題。
摘自wiki
隊頭阻塞(Head-of-line blocking或縮寫為HOL blocking)在計算機網(wǎng)絡的范疇中是一種性能受限的現(xiàn)象。它的原因是一列的第一個數(shù)據(jù)包(隊頭)受阻而導致整列數(shù)據(jù)包受阻。例如它有可能在緩存式輸入的交換機中出現(xiàn),有可能因為傳輸順序錯亂而出現(xiàn),亦有可能在HTTP流水線中有多個請求的情況下出現(xiàn)。
我們還是使用上面的例子來進行解釋,這次的握手請求就變了,A一次向B發(fā)出了三個請求:
三次握手:
A→B:今晚下班一起吃飯、逛街、看電影嗎?
B→A:好的,今晚下班一起吃飯、逛街、看電影。
A→B:好的,我知道你答應我今晚下班一起吃飯、逛街、看電影的邀請了。
實際上這樣子是有很大的風險的
如果是按照長連接模型,A可以根據(jù)B在吃飯的時候的反應來決定要不要繼續(xù)去逛街看電影,也就是如果傳輸完了一次數(shù)據(jù)之后還保持連接就繼續(xù)傳輸,萬一連接突然斷開或者是不穩(wěn)定,那可能就要重新建立連接。(萬一B在吃飯的時候吃的不開心不想繼續(xù)逛街看電影那就等下次再吃飯逛街看電影)
但是如果按照流水線模型,A一次發(fā)送三個請求,雖然發(fā)送請求的時候省事兒了(三次握手的時候TCP打包傳輸請求更省事),但是誰也不知道吃飯逛街看電影的過程中會發(fā)生什么意外,時間越長越不穩(wěn)定,而且還容易出現(xiàn)萬一B想減肥不想吃飯,只想逛街看電影的情況呢?(HOL問題)
最后這里補充一張圖片來對比三種模型之間的差別:
2、Nginx中的keepalive指令
當我們配置Nginx作為代理服務器的時候,想要支持HTTP長連接,需要client到Nginx和Nginx到server都是長連接,因為此時Nginx既是client的server也是server的client。
了解了上面的原理之后,Nginx中的keepalive指令我們就非常好理解了,相關的指令主要有三個,我們逐個進行解釋:
2.1 keepalive
Syntax: keepalive connections; Default: — Context: upstream This directive appeared in version 1.1.4.在upstream模塊中配置,啟用連接到upstream中的服務器的緩存,connections參數(shù)的主要作用是設定每個Nginx的**單個worker進程(each worker process)**對于upstream中的server的最大空閑連接數(shù),當超過該數(shù)字的時候,會關閉使用得最少的連接。
-
對于HTTP,應將proxy_http_version指令設置為“ 1.1”,并且應清除Connection標題字段
-
對于FastCGI服務器,需要設置fastcgi_keep_conn以啟用keepalive連接
需要注意的是,keepalive指令并不會限制Nginx的所有worker進程能開啟的連接到upstream服務器中的連接總數(shù)(total number)。也就是如果設得太大了,會導致過多的空閑連接占滿了upstream中的server資源,導致新的連接無法建立,因此這個數(shù)值的設定需要根據(jù)worker進程數(shù)量來調(diào)整。
2.2 keepalive_requests
Syntax: keepalive_requests number; Default: keepalive_requests 100; Context: upstream This directive appeared in version 1.15.3.keepalive_requests設定可以通過一個連接(connection)發(fā)送的請求(request)數(shù)量,超過最大請求數(shù)量之后,該連接會被關閉。為了釋放每個連接的內(nèi)存分配,定期關閉連接是很有必要的。因此,不建議將keepalive_requests設定過大,否則可能會導致過高的內(nèi)存占用。
2.3 keepalive_timeout
Syntax: keepalive_timeout timeout; Default: keepalive_timeout 60s; Context: upstream This directive appeared in version 1.15.3.設定連接超時時間,在此設定的時間內(nèi),client與upstream中的server的空閑keepalive連接將保持打開狀態(tài)(open)。此外,雖然官方文檔說的默認值是60s,但是1.17.9版本的Nginx在安裝之后配置文件nginx.conf上面設定的是65s。
總結(jié)
以上是生活随笔為你收集整理的Nginx篇05-http长连接和keeplive的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [爬虫][python][入门][网页源
- 下一篇: Unity3D研究院之Android同步