前言
- 測試服務器系統:ubuntu server 20.04.3
- nginx負載均衡服務器:centos 7
- 服務器上我放了一個web系統用來測試連接數:開源的支持高並發的服務器
- 發出請求的是我的電腦,電腦系統:win7
- 發出請求用的是python的壓測工具:locust
TCP連接能連接多少
要想弄清楚一個服務器能接受多少連接數,就需要根據socket五元組來看,即源IP+源端口+目標IP+目標端口+類型(TCP/UDP)。只要五元組不重復,就可以新增tcp連接。不過由於測試的時候一般類型都是相同的,所有大多數都是稱為四元組。
由於服務器的IP和web系統的端口一般是固定的,每個客戶端的IP又不相同,那么照這樣看連接數應該基本上相當於沒限制才對。其實不然,實際上每個連接還要占用一定的內存和一個文件描述符。
那么一個TCP socket占用多少內存呢?
大約是3K多,當然如果有發送或者接收的緩存區文件存在則另算,在響應較快、緩存文件不大的情況下內存應該不會成為瓶頸。
服務器又能打開多少文件描述符呢?
可以通過以下命令查看
系統級:當前系統可打開的最大數量,通過 cat /proc/sys/fs/file-max
查看
用戶級:指定用戶可打開的最大數量,通過 cat /etc/security/limits.conf
查看
進程級:單個進程可打開的最大數量,通過 cat /proc/sys/fs/nr_open
查看
修改方式
修改單個進程可打開的最大文件描述符為10000,即可打開10000個連接:echo 10000 > /proc/sys/fs/nr_open
用戶級修改:
sudo vi /etc/security/limits.conf
root soft nofile 65533
root hard nofile 65533
# root為指定修改的用戶,soft為軟限制,hard為硬限制,一般軟限制要小於或等於硬限制
當然,每創建一個tcp連接,還需要消耗一個線程來處理(也可以采用IO多路復用的方式,一個線程管理多個TCP連接),所以和CPU也有關系,不能通過單純的提高內存的方式來增加連接數。
常用查看連接數命令:
netstat -nat | grep -i "8085" | wc -l # 查詢指定端口的連接數
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' # 查看TCP連接數及狀態命令
實際測試
此時是使用我的電腦向nginx負載均衡服務器發送請求,然后轉發給web服務器。
測試1 未調整的情況下測試
客戶端情況:
初始:可用端口55000個,性能夠用
結果:本地性能未達瓶頸,但是設置的1000並發人數,請求數平均只有437.3。
nginx服務器情況:
初始:可用端口60000個,用戶級65535,性能夠用
結果:本地性能未達瓶頸,但是出現很多TIME_WAIT數,最高時8000多。
服務器情況:
初始:用戶級65535。
結果:最高連接數23,平均2.
測試1分析
先分析一下TIME_WAIT、CLOSE_WAIT出現的原因及解決方法
分析這里,就必須要簡短回顧一下四次揮手(當client發起結束請求時)
簡短來說:
1、一端沒有close,那么另一端將有大量的close_wait狀態;
2、主動close的一端,在量特別大的情況下將造成大量的time_wait狀態(由於Linux中一般默認的2msl為60s,那么正常情況下每秒1000的請求會造成60*1000=60000個time_wait記錄,幾百幾千問題不大)
既然主動close的一方才會有time_wait記錄,那么這里就說明nginx服務器是主動關閉的一方,那nginx服務器關閉的對象又是誰呢?
在僅修改了nginx的代理地址,未改變其他配置情況下,通過wireshark抓包得知:
- 客戶端與nginx端相互通信都是http/1.1的鏈接,這里是nginx端先發起的fin請求;
- nginx端到服務器端的請求是http/1.0,服務器端返回的請求是http/1.1,這里是nginx端先發起的fin請求。
測試1優化
依上面的場景分析,如果要減少time_wait數,提高連接數,則需要從以下方面來解決
- 調整負載均衡服務器和web服務器/etc/sysctl.conf下的net.ipv4.ip_local_port_range配置,修改成
net.ipv4.ip_local_port_range=1024 65535
,保證至少可以使用6萬個隨機端口,就算保留1分鍾,也能支持每秒1000的並發; - 加多負載均衡服務器的ip,直接翻番;
- 負載均衡與服務器端也建立長連接,不關閉就不會有等待;
- 擴大nginx的keep-alive超時時間,最大請求數,使得長連接不會這么早關閉;
- 在nginx服務器上調整time_wait參數net.ipv4.tcp_tw_reuse=1,盡可能去復用連接(另外net.ipv4.tcp_tw_recycle參數在4.10以上內核中被移除了)。
另外還有一些參數可以調整,不過一般默認是夠用的
net.ipv4.tcp_syncookies = 1 # 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉;
net.ipv4.tcp_keepalive_time = 1200 #表示當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時,改為20分鍾。
net.ipv4.tcp_max_syn_backlog = 8192 #表示SYN隊列的長度,默認為1024,加大隊列長度為8192,可以容納更多等待連接的網絡連接數。
net.ipv4.tcp_max_tw_buckets = 5000 #表示系統同時保持TIME_WAIT套接字的最大數量,如果超過這個數字,TIME_WAIT套接字將立刻被清除並打印警告信息。
#默認為180000,改為5000。對於Apache、Nginx等服務器,上幾行的參數可以很好地減少TIME_WAIT套接字數量,。
待優化測試驗證