一次TCP TIME_WAIT連接數(shù)過多告警處理
問題回顧
客戶反饋收到如下告警,主機(jī)TCP timewait連接數(shù)過多
prometheus告警表達(dá)式
node_sockstat_TCP_tw > 50000
收到連接數(shù)過多的告警并不代表一定會(huì)產(chǎn)生生產(chǎn)問題,此時(shí)要關(guān)注負(fù)載是否直線上升,連接數(shù)一直無(wú)法釋放,如果出現(xiàn)此情況,則需要及時(shí)處理,避免造成生產(chǎn)環(huán)境宕機(jī)。
連接數(shù)數(shù)據(jù)來(lái)源:/proc/net/sockstat
線上場(chǎng)景中,持續(xù)的高并發(fā)場(chǎng)景
- 一部分 TIME_WAIT 連接被回收,但新的 TIME_WAIT 連接產(chǎn)生,新產(chǎn)生的連接數(shù)超過釋放的速度;
- 一些極端情況下,會(huì)出現(xiàn)大量的 TIME_WAIT 連接。
Think:上述大量的 TIME_WAIT 狀態(tài) TCP 連接,有什么業(yè)務(wù)上的影響嗎?
Nginx 作為反向代理時(shí),大量的短鏈接,可能導(dǎo)致 Nginx 上的 TCP 連接處于 time_wait 狀態(tài):
每一個(gè) time_wait 狀態(tài),都會(huì)占用一個(gè)「本地端口」,上限為 65535
當(dāng)大量的連接處于 time_wait 時(shí),新建立 TCP 連接會(huì)出錯(cuò),address already in use : connect 異常
Tips:TCP 本地端口數(shù)量,上限為 65535(6.5w),這是因?yàn)?TCP 頭部使用 16 bit,存儲(chǔ)「端口號(hào)」,因此約束上限為 65535。
圖片
- time_wait 狀態(tài)的影響
TCP 連接中,「主動(dòng)發(fā)起關(guān)閉連接」的一端,會(huì)進(jìn)入 time_wait 狀態(tài)
time_wait 狀態(tài),默認(rèn)會(huì)持續(xù) 2 MSL(報(bào)文的最大生存時(shí)間)
time_wait 狀態(tài)下,TCP 連接占用的端口,無(wú)法被再次使用
TCP 端口數(shù)量,上限是 6.5w(65535,16 bit)
net.ipv4.ip_local_port_range = 1024 65000 #端口數(shù)和這個(gè)參數(shù)有關(guān)系
大量 time_wait 狀態(tài)存在,會(huì)導(dǎo)致新建 TCP 連接會(huì)出錯(cuò),address already in use : connect 異常
大量的連接會(huì)導(dǎo)致服務(wù)器資源使用上升
- 現(xiàn)實(shí)場(chǎng)景
服務(wù)內(nèi)部調(diào)用過多,優(yōu)化業(yè)務(wù)模式,也可以是連接關(guān)閉方式需要優(yōu)化
Nginx 反向代理場(chǎng)景中,可能出現(xiàn)大量短鏈接,服務(wù)器端可能存在
- 解決思路
1、服務(wù)器端允許 time_wait 狀態(tài)的 socket 被重用
2、縮減 time_wait 時(shí)間,設(shè)置為 1 MSL(即,2 mins)
解決方案
TCP連接數(shù)統(tǒng)計(jì)腳本
#!/bin/sh
for i in /proc/* ;
do
if [ -d $i/fd ];then
echo $i $(ls $i/fd -l | grep socket: |wc -l)
fi
done
通過這個(gè)腳本可以統(tǒng)計(jì)出當(dāng)前分配連接數(shù)的進(jìn)程,通過進(jìn)程可以找到對(duì)應(yīng)的服務(wù),如果是服務(wù)關(guān)閉連接的姿勢(shì)不對(duì),業(yè)務(wù)方優(yōu)化即可
在業(yè)務(wù)側(cè)解決此問題之前,我們可以通過操作系統(tǒng)的內(nèi)核參數(shù)緩解此問題
方案
修改配置文件/etc/sysctl.conf
1、允許將TIME_WAIT狀態(tài)的socket重新用于新的TCP連接
net.ipv4.tcp_tw_reuse = 1 #默認(rèn)為0,表示關(guān)閉,如果為0,修改為1
2、快速回收TIME_WAIT狀態(tài)的socket
net.ipv4.tcp_tw_recycle = 1 #修改為1,默認(rèn)為0
3、修改time_wait連接數(shù)的回收時(shí)間
cat /proc/sys/net/ipv4/tcp_fin_timeout #查看默認(rèn)的MSL值
net.ipv4.tcp_fin_timeout = 30 #如果為60,修改為30s回收
最后sudo sysctl -p 使配置生效即可,從修改前后的效果上可以看到,timewait的回收明顯加快了