原文:https://blog.csdn.net/qq_34556414/article/details/106116889
作者:富士康質檢員張全蛋
nginx長連接-keepalive
當使用nginx作為反向代理時,為了支持長連接,需要做到兩點:
-
從client到nginx的連接是長連接
-
從nginx到server的連接是長連接
worker_connections
Syntax: | worker_connections |
---|---|
Default: | worker_connections 512; |
Context: | events |
Sets the maximum number of simultaneous connections that can be opened by a worker process.
It should be kept in mind that this number includes all connections (e.g. connections with proxied servers, among others), not only connections with clients. Another consideration is that the actual number of simultaneous connections cannot exceed the current limit on the maximum number of open files, which can be changed by worker_rlimit_nofile.
這個默認的512是非常小的,因為nginx處理都是以萬來計算,所以我們是要去修改的。同時也寫的很清楚,這個連接不僅僅用於客戶端的連接還用於面向服務器的,所以做反向代理的時候每個客戶端會消耗2個connection。當配置了更大的worker connection時候,也就意味着Nginx使用了更大的內存。同時每個worker connection都對應着讀事件和寫事件
Syntax: | worker_rlimit_nofile |
---|---|
Default: | — |
Context: | main |
Changes the limit on the maximum number of open files (RLIMIT_NOFILE) for worker processes. Used to increase the limit without restarting the main process.
保持和client的長連接
默認情況下,nginx已經自動開啟了對client連接的keep alive支持(同時client發送的HTTP請求要求keep alive)。一般場景可以直接使用,但是對於一些比較特殊的場景,還是有必要調整個別參數(keepalive_timeout和keepalive_requests)。
http { keepalive_timeout 60s; keepalive_requests 10000; }
1) keepalive_timeout:
語法:keepalive_timeout timeout [header_timeout];
第一個參數:設置keep-alive客戶端連接在服務器端保持開啟的超時值(默認75s);值為0會禁用keep-alive客戶端連接;
第二個參數:可選、在響應的header域中設置一個值“Keep-Alive: timeout=time”;通常可以不用設置;
注:keepalive_timeout默認75s,一般情況下也夠用,對於一些請求比較大的內部服務器通訊的場景,適當加大為120s或者300s;
2)keepalive_requests:
keepalive_requests指令用於設置一個keep-alive連接上可以服務的請求的最大數量,當最大請求數量達到時,連接被關閉。默認是100。這個參數的真實含義,是指一個keep alive建立之后,nginx就會為這個連接設置一個計數器,記錄這個keep alive的長連接上已經接收並處理的客戶端請求的數量。如果達到這個參數設置的最大值時,則nginx會強行關閉這個長連接,逼迫客戶端不得不重新建立新的長連接。
大多數情況下當QPS(每秒請求數)不是很高時,默認值100湊合夠用。但是,對於一些QPS比較高(比如超過10000QPS,甚至達到30000,50000甚至更高) 的場景,默認的100就顯得太低。
簡單計算一下,QPS=10000時,客戶端每秒發送10000個請求(通常建立有多個長連接),每個連接只能最多跑100次請求,意味着平均每秒鍾就會有100個長連接因此被nginx關閉。同樣意味着為了保持QPS,客戶端不得不每秒中重新新建100個連接。因此,就會發現有大量的TIME_WAIT的socket連接(即使此時keep alive已經在client和nginx之間生效)。因此對於QPS較高的場景,非常有必要加大這個參數,以避免出現大量連接被生成再拋棄的情況,減少TIME_WAIT。
保持和server的長連接
為了讓nginx和后端server(nginx稱為upstream)之間保持長連接,典型設置如下:(默認nginx訪問后端都是用的短連接(HTTP1.0),一個請求來了,Nginx 新開一個端口和后端建立連接,后端執行完畢后主動關閉該鏈接)
http { upstream BACKEND { server 192.168.0.1:8080 weight=1 max_fails=2 fail_timeout=30s; server 192.168.0.2:8080 weight=1 max_fails=2 fail_timeout=30s; keepalive 300; // 這個很重要! } server { listen 8080 default_server; server_name ""; location / { proxy_pass http://BACKEND; proxy_set_header Host $Host; proxy_set_header x-forwarded-for $remote_addr; proxy_set_header X-Real-IP $remote_addr; add_header Cache-Control no-store; add_header Pragma no-cache; proxy_http_version 1.1; // 這兩個最好也設置 proxy_set_header Connection ""; } } }
1)location中有兩個參數需要設置:
http { server { location / { proxy_http_version 1.1; // 這兩個最好也設置 proxy_set_header Connection ""; } } }
HTTP協議中對長連接的支持是從1.1版本之后才有的,因此最好通過proxy_http_version指令設置為”1.1”;
而”Connection” header應該被清理。清理的意思,我的理解,是清理從client過來的http header,因為即使是client和nginx之間是短連接,nginx和upstream之間也是可以開啟長連接的。這種情況下必須清理來自client請求中的”Connection” header。
2)upstream中的keepalive設置:
此處keepalive的含義不是開啟、關閉長連接的開關;也不是用來設置超時的timeout;更不是設置長連接池最大連接數。官方解釋:
1. The connections parameter sets the maximum number of idle keepalive connections to upstream servers connections(設置到upstream服務器的空閑keepalive連接的最大數量)
2. When this number is exceeded, the least recently used connections are closed. (當這個數量被突破時,最近使用最少的連接將被關閉)
3. It should be particularly noted that the keepalive directive does not limit the total number of connections to upstream servers that an nginx worker process can open.(特別提醒:keepalive指令不會限制一個nginx worker進程到upstream服務器連接的總數量)
我們先假設一個場景: 有一個HTTP服務,作為upstream服務器接收請求,響應時間為100毫秒。如果要達到10000 QPS的性能,就需要在nginx和upstream服務器之間建立大約1000條HTTP連接。nginx為此建立連接池,然后請求過來時為每個請求分配一個連接,請求結束時回收連接放入連接池中,連接的狀態也就更改為idle。我們再假設這個upstream服務器的keepalive參數設置比較小,比如常見的10.
A、假設請求和響應是均勻而平穩的,那么這1000條連接應該都是一放回連接池就立即被后續請求申請使用,線程池中的idle線程會非常的少,趨進於零,不會造成連接數量反復震盪。
B、顯示中請求和響應不可能平穩,我們以10毫秒為一個單位,來看連接的情況(注意場景是1000個線程+100毫秒響應時間,每秒有10000個請求完成),我們假設應答始終都是平穩的,只是請求不平穩,第一個10毫秒只有50,第二個10毫秒有150:
1. 下一個10毫秒,有100個連接結束請求回收連接到連接池,但是假設此時請求不均勻10毫秒內沒有預計的100個請求進來,而是只有50個請求。注意此時連接池回收了100個連接又分配出去50個連接,因此連接池內有50個空閑連接。
2. 然后注意看keepalive=10的設置,這意味着連接池中最多容許保留有10個空閑連接。因此nginx不得不將這50個空閑連接中的40個關閉,只留下10個。
3. 再下一個10個毫秒,有150個請求進來,有100個請求結束任務釋放連接。150 - 100 = 50,空缺了50個連接,減掉前面連接池保留的10個空閑連接,nginx不得不新建40個新連接來滿足要求。
C、同樣,如果假設相應不均衡也會出現上面的連接數波動情況。
造成連接數量反復震盪的一個推手,就是這個keepalive 這個最大空閑連接數。畢竟連接池中的1000個連接在頻繁利用時,出現短時間內多余10個空閑連接的概率實在太高。因此為了避免出現上面的連接震盪,必須考慮加大這個參數,比如上面的場景如果將keepalive設置為100或者200,就可以非常有效的緩沖請求和應答不均勻。
總結
keepalive 這個參數一定要小心設置,尤其對於QPS比較高的場景,推薦先做一下估算,根據QPS和平均響應時間大體能計算出需要的長連接的數量。比如前面10000 QPS和100毫秒響應時間就可以推算出需要的長連接數量大概是1000. 然后將keepalive設置為這個長連接數量的10%到30%。比較懶的同學,可以直接設置為keepalive=1000之類的,一般都OK的了。
綜上,出現大量TIME_WAIT的情況
1)導致 nginx端出現大量TIME_WAIT的情況有兩種:
- keepalive_requests設置比較小,高並發下超過此值后nginx會強制關閉和客戶端保持的keepalive長連接;(主動關閉連接后導致nginx出現TIME_WAIT)
- keepalive設置的比較小(空閑數太小),導致高並發下nginx會頻繁出現連接數震盪(超過該值會關閉連接),不停的關閉、開啟和后端server保持的keepalive長連接;
2)導致后端server端出現大量TIME_WAIT的情況:
nginx沒有打開和后端的長連接,即:沒有設置proxy_http_version 1.1;和proxy_set_header Connection “”;從而導致后端server每次關閉連接,高並發下就會出現server端出現大量TIME_WAIT