天天看點

Nginx對用戶端和server端長連接配接控制keepalive(轉)

原文:https://blog.csdn.net/qq_34556414/article/details/106116889

作者:富士康質檢員張全蛋

nginx長連接配接-keepalive

當使用nginx作為反向代理時,為了支援長連接配接,需要做到兩點:

  • 從client到nginx的連接配接是長連接配接
  • 從nginx到server的連接配接是長連接配接
Nginx對用戶端和server端長連接配接控制keepalive(轉)

worker_connections

Syntax:

worker_connections 

number

;

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都對應着讀事件和寫事件

worker_rlimit_nofile 

number

;

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

繼續閱讀