在服務端,連接達到一定數量,諸如50W時,有些隱藏很深的問題,就不斷的拋出來。 通過查看dmesg命令查看,發現大量TCP: too many of orphaned sockets錯誤,也很正常,下面到了需要調整tcp socket參數的時候了。
第一個需要調整的是tcp_rmem,即TCP讀取緩沖區,單位為字節,查看默認值
- cat /proc/sys/net/ipv4/tcp_rmem
- 4096 87380 4161536
默認值為87380 byte ≈ 86K,最小為4096 byte=4K,最大值為4064K。
第二個需要調整的是tcp_wmem,發送緩沖區,單位是字節,默認值
- cat /proc/sys/net/ipv4/tcp_wmem
- 4096 16384 4161536
解釋同上
第三個需要調整的tcp_mem,調整TCP的內存大小,其單位是頁,1頁等於4096字節。系統默認值:
- cat /proc/sys/net/ipv4/tcp_mem
- 932448 1243264 1864896
tcp_mem(3個INTEGER變量):low, pressure, high
- low:當TCP使用了低於該值的內存頁面數時,TCP不會考慮釋放內存。
- pressure:當TCP使用了超過該值的內存頁面數量時,TCP試圖穩定其內存使用,進入pressure模式,當內存消耗低於low值時則退出pressure狀態。
- high:允許所有tcp sockets用於排隊緩沖數據報的頁面量,當內存占用超過此值,系統拒絕分配socket,后台日志輸出“TCP: too many of orphaned sockets”。
一般情況下這些值是在系統啟動時根據系統內存數量計算得到的。 根據當前tcp_mem最大內存頁面數是1864896,當內存為(1864896*4)/1024K=7284.75M時,系統將無法為新的socket連接分配內存,即TCP連接將被拒絕。
實際測試環境中,據觀察大概在99萬個連接左右的時候(零頭不算),進程被殺死,觸發out of socket memory錯誤(dmesg命令查看獲得)。每一個連接大致占用7.5K內存(下面給出計算方式),大致可算的此時內存占用情況(990000 * 7.5 / 1024K = 7251M)。
這樣和tcp_mem最大頁面值數量比較吻合,因此此值也需要修改。
三個TCP調整語句為:
- echo "net.ipv4.tcp_mem = 786432 2097152 3145728">> /etc/sysctl.conf
- echo "net.ipv4.tcp_rmem = 4096 4096 16777216">> /etc/sysctl.conf
- echo "net.ipv4.tcp_wmem = 4096 4096 16777216">> /etc/sysctl.conf
備注: 為了節省內存,設置tcp讀、寫緩沖區都為4K大小,tcp_mem
三個值分別為3G 8G 16G,tcp_rmem
和tcp_wmem
最大值也是16G。
目標達成
經過若干次的嘗試,最終達到目標,1024000個持久連接。1024000數字是怎么得來的呢,兩台物理機器各自發出64000個請求,兩個配置為6G左右的centos測試端機器(綁定7個橋接或NAT連接)各自發出640007 = 448000。也就是 1024000 = (64000) + (64000) + (640007) + (64000*7), 共使用了16個網卡(物理網卡+虛擬網卡)。
終端輸出
- ......
- online user 1023990
- online user 1023991
- online user 1023992
- online user 1023993
- online user 1023994
- online user 1023995
- online user 1023996
- online user 1023997
- online user 1023998
- online user 1023999
- online user 1024000
在線用戶目標達到1024000個!
服務器狀態信息
服務啟動時內存占用:
total used free shared buffers cached Mem: 10442 271 10171 0 22 78 -/+ buffers/cache: 171 10271 Swap: 8127 0 8127
系統達到1024000個連接后的內存情況(執行三次 free -m 命令,獲取三次結果):
total used free shared buffers cached Mem: 10442 7781 2661 0 22 78 -/+ buffers/cache: 7680 2762 Swap: 8127 0 8127 total used free shared buffers cached Mem: 10442 7793 2649 0 22 78 -/+ buffers/cache: 7692 2750 Swap: 8127 0 8127 total used free shared buffers cached Mem: 10442 7804 2638 0 22 79 -/+ buffers/cache: 7702 2740 Swap: 8127 0 8127
這三次內存使用分別是7680,7692,7702,這次不取平均值,取一個中等偏上的值,定為7701M。那么程序接收1024000個連接,共消耗了 7701M-171M = 7530M內存, 7530M*1024K / 1024000 = 7.53K, 每一個連接消耗內存在為7.5K左右,這和在連接達到512000時所計算較為吻合。
虛擬機運行Centos內存占用,不太穩定,但一般相差不大,以上數值,僅供參考。
執行top -p 某刻輸出信息:
- top - 17:23:17 up 18 min, 4 users, load average: 0.33, 0.12, 0.11
- Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
- Cpu(s): 0.2%us, 6.3%sy, 0.0%ni, 80.2%id, 0.0%wa, 4.5%hi, 8.8%si, 0.0%st
- Mem: 10693580k total, 6479980k used, 4213600k free, 22916k buffers
- Swap: 8323056k total, 0k used, 8323056k free, 80360k cached
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 2924 yongboy 20 0 82776 74m 508 R 51.3 0.7 3:53.95 server
執行vmstate:
- vmstat
- procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
- r b swpd free buff cache si so bi bo in cs us sy id wa st
- 0 0 0 2725572 23008 80360 0 0 21 2 1012 894 0 9 89 2 0
獲取當前socket連接狀態統計信息:
- cat /proc/net/sockstat
- sockets: used 1024380
- TCP: inuse 1024009 orphan 0 tw 0 alloc 1024014 mem 2
- UDP: inuse 11 mem 1
- UDPLITE: inuse 0
- RAW: inuse 0
- FRAG: inuse 0 memory 0
獲取當前系統打開的文件句柄:
- sysctl -a | grep file
- fs.file-nr = 1025216 0 1048576
- fs.file-max = 1048576
此時任何類似於下面查詢操作都是一個慢,等待若干時間還不見得執行完畢。
- netstat -nat|grep -i "8000"|grep ESTABLISHED|wc -l
- netstat -n | grep -i "8000" | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
以上兩個命令在二三十分鍾過去了,還未執行完畢,只好停止。
小結
本次從頭到尾的測試,所需要有的linux系統需要調整的參數也就是那么幾個,匯總一下:
echo "* - nofile 1048576" >> /etc/security/limits.conf echo "fs.file-max = 1048576" >> /etc/sysctl.conf echo "net.ipv4.ip_local_port_range = 1024 65535" >> /etc/sysctl.conf echo "net.ipv4.tcp_mem = 786432 2097152 3145728" >> /etc/sysctl.conf echo "net.ipv4.tcp_rmem = 4096 4096 16777216" >> /etc/sysctl.conf echo "net.ipv4.tcp_wmem = 4096 4096 16777216" >> /etc/sysctl.conf
其它沒有調整的參數,僅僅因為它們暫時對本次測試沒有帶來什么影響,實際環境中需要結合需要調整類似於SO_KEEPALIVE、tcpmax_orphans等大量參數。