最近遇到一個非常有趣的問題。其中有一組HAProxy,經常出現問題。登入上伺服器,cpu、記憶體、網路、io一頓猛查。最後發現有超過6萬個連線處於機器的TIME_WAIT狀態。
TIME_WAIT狀態,通常會出現在HAProxy、Nginx這種代理機器上,主要是因為頻繁的主動關閉所造成的。透過修改reuse和回收參數,可以比較快速的解決問題。
網路狀態的統計數量,可以使用下面的命令進行統計。
netstat -ant|awk '/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}' ESTABLISHED 70 FIN_WAIT2 30 CLOSING 33 TIME_WAIT 65520
這本來沒什麼神奇的,但65535這個數字,實在是太過於敏感。應該是觸發了某種上限。
使我們更加感到疑惑的是:為什麼TIME_WAIT狀態的連接,僅僅達到了65535,服務就不可用了?
到處號稱的單機百萬連接,是在吹牛皮麼?怎麼這麼經不起折騰?
65535,表示等於2的16次方減一,是一個神奇的數字。把這個小數字暫且擱置,我們先來了解Linux支援多大的連線容量。
1. Linux能夠支援多少連線?
答案是無數個。可是埠只有65535個啊。
為什麼連接埠只有65535個?
TCP和UDP協定在開頭分別用16位元儲存來源埠號和目標埠號,這是基於歷史原因。很遺憾的是,這個值是short類型的,大小也是2^16-1。
因為歷史原因造成的不可改變的標準,就是那麼根深蒂固。
那Linux到底能支援多少個連結呢?答案是無數個。
拿nginx來說,我們把它監聽在80埠上。這時候A機器去連接Nginx,可以發起多達6w多條長連線。如果B機器去連接Nginx,同樣也可以發起6w多個連線。這是由於確定一條連接,是由src和dst來共同決定的。
認為Linux只能接受65535條連結的想法,只能說是犯了非常淺顯的想當然主義。
65535個端口,作為壓測機可能對你來說太小了一些。但對於伺服器來說,已經綽綽有餘了。
2. 如何支援百萬連接?
從上面可以看到,連接數,是沒有限制的。但Linux還有一層防護,那就是檔案句柄數。透過lsof指令查看到的那些東西,就是所謂的檔案句柄。
先來看幾個指令的展示。
ulmit,展示了每個行程所能佔用的檔案句柄數量。
ulimit -n 65535
file-max,展示了作業系統能夠佔用的檔案句柄數量總和,針對的是所有的進程。
cat /proc/sys/fs/file-max 766722
file-nr,展示了目前已經使用的句柄數量和總的句柄數量。可以拿來做監控。
cat /proc/sys/fs/file-nr 1824 0 766722
為了支援百萬連接,需要釋放作業系統層級的句柄和進程層級的句柄。也就是說,ulimit和file-max的顯示,都要大於百萬才成。
3. 如何設定?
雖然常用的方案是ulimit來設定進程句柄數,但我非常不建議使用。只有在同一shell中啟動的進程,才會受到ulimit設定的影響,原因沒有其他的。如果你打開另一個shell或重新啟動機器,那麼ulimit的變更都會消失。就是下面這種方式:
ulimit -n 1000000
正確的方式,就是修改/etc/security/limits.conf檔。比如下面的內容。
root soft nofile 1000000 root hard nofile 1000000 * soft nofile 1000000 * hard nofile 1000000
可以看到,我們可以針對於特定的用戶,修改其句柄數量。這在安裝es等應用程式時,常碰到。
es - nofile 65535
使用這種方法,仍需要開啟一個新的shell才能進行操作。這個指令無論是在修改後的shell還是在修改之前的shell中,都不會生效。 xjjdog曾經遇到多個案例,儘管限制已經放開,但仍發生了問題。
查看進程的記憶體映射檔案可以確定這些變更是否已經生效。例如,在指令「cat /proc/180323/limits」中,將會展示詳細資訊。
這個數值,也不是想要設多大就多大的。它的大小上限,是由nr_open決定的。要增加大小,需要在/ect/sysct.conf中更改fs.nr_open的值。
cat /proc/sys/fs/nr_open 1048576
如果想要修改file-max參數,建議在/etc/sysctl.conf檔案中加入以下內容。足足有6百多萬!
fs.file-max = 6553560
當檔案數量超出的時候,就會報kernel: VFS: file-max limit 65535 reached的錯誤。
總結一下。
Linux即使放開一個端口,能夠接受的連接也是海量的。這些連線的上限,受到單一進程檔案句柄數量和作業系統檔案句柄數量的限制,也就是ulimit和file-max。
為了能夠將參數修改持久化,我們傾向於將改動寫入到檔案中。行程的檔案句柄限制,可以放在/etc/security/limits.conf中,它的上限受到fs.nr_open的限制;作業系統的檔案句柄限制,可以放到/etc/sysctl.conf檔案中。最終,一定要檢查/proc/$id/limits文件,確認修改是否生效於進程。
以上是Ulimit的故障怎麼解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!