100萬併發鏈接服務器筆記之1M併發鏈接目標達成

第四個遇到的問題:tcp_mem

在服務端,鏈接達到必定數量,諸如50W時,有些隱藏很深的問題,就不斷的拋出來。 經過查看dmesg命令查看,發現大量TCP: too many of orphaned sockets錯誤,也很正常,下面到了須要調整tcp socket參數的時候了。 linux

第一個須要調整的是tcp_rmem,即TCP讀取緩衝區,單位爲字節,查看默認值 centos

cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 4161536

默認值爲87380bit ≈ 86K,最小爲4096bit=4K,最大值爲4064K。 服務器

第二個須要調整的是tcp_wmem,發送緩衝區,單位是字節,默認值 socket

cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4161536

解釋同上 tcp

第三個須要調整的tcp_mem,調整TCP的內存大小,其單位是頁,1頁等於4096字節。系統默認值: 測試

cat /proc/sys/net/ipv4/tcp_mem
932448 1243264 1864896

tcp_mem(3個INTEGER變量):low, pressure, high spa

  • 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)。 code

這樣和tcp_mem最大頁面值數量比較吻合,所以此值也須要修改。 server

三個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 "yongboy soft nofile 1048576" >> /etc/security/limits.conf 
    echo "yongboy hard 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等大量參數。

本文表明一次實踐,不足之處,歡迎批評指正。

相關文章
相關標籤/搜索