一、系統環境
操作系統: Centos 6.4 64bit
zabbix-agent 版本: Zabbix agent v2.2.7 (revision 50148) (24 October 2014)
二、出現的問題
zabbix-agent機器上,發現TIME_WAIT過多

三、為什么會出現這么多TIME_WAIT
下表說明了zabbix是如何通信的, 它會教給你基本的tcp協議的知識。如果你看不懂這個表的內容,我建議你可以讀下<TCP/IP 詳解1>!
表格中的state是TCP連接在agent和server不同階段時的狀態。我們假設每個階段,agent和server都會得到正確的狀態!
如果你用tcpdump捕獲通信數據,你可以轉儲到文件,下載桌面,然后通過Wireshark 來查看!
passive agent通信的過程如下:
| Number | Connection state agent | Connection state server | Direction | TCP flags | Purpose of TCP segment |
|---|---|---|---|---|---|
| 1 | LISTEN | SYN_SENT | Agent<-Server | SYN | 初始化TCP連接,第一次tcp握手 |
| 2 | SYN_RECVD | SYN_SENT | Agent->Server | SYN, ACK | 接受連接 |
| 3 | SYN_RECVD | ESTABLISHED | Agent<-Server | ACK | 連接已經建立 |
| 4 | ESTABLISHED | ESTABLISHED | Agent<-Server | PSH, ACK | zabbix server發送item key 給agent |
| 5 | ESTABLISHED | ESTABLISHED | Agent->Server | ACK | Agent 確認收到 |
| 6 | ESTABLISHED | ESTABLISHED | Agent->Server | PSH, ACK | agent發送對應item key的數據 |
| 7 | FIN_WAIT_1 | ESTABLISHED | Agent->Server | FIN, PSH, ACK | 當沒有其它數據要發送的時候, agent 關閉連接 |
| 8 | FIN_WAIT_1 | CLOSE_WAIT | Agent<-Server | ACK | |
| 9 | FIN_WAIT_2 | LAST_ACK | Agent<-Server | FIN, ACK | |
| 10 | TIME_WAIT | LAST_ACK | Agent->Server | ACK | 連接已經完全關閉 |
| 11 | CLOSED | CLOSED | - | - | 最終,兩邊的狀態都為CLOSED |
- 1: tcp連接是通過socket通信的,每個socket都是為唯一的,address:port--address:port
- 2: 第二行的SYN/ACK如果沒有發送,那么第一步的SYN會重新發送。在缺省的timeout設置中,如果丟了這個SYN/ACK過程,連接將會被重置(RST),並且這個獲取數據的過程將會失敗!
- 3: 當前的連接是全雙工的工作模式
- 4: PUSH標志表明當前正在傳送數據!
- 7: 沒有其它事要做,關閉連接。在接下來的關閉過程中,agent會保留TIME_WAIT狀態!請去看下TCP連接的3次握手,和TCP關閉的4次揮手過程。 這里並不是正確的連接關閉過程。
- 8: 帶有FIN標志的數據報會被立刻確認,然后zabbix server 立刻知道這個連接已經關閉。
- 9: zabbix server確認連接關閉的時候,它也會立刻發送一個帶FIN的數據包
- 10: 立刻確認第九步的FIN,到此為止,這個連接就關閉了!
- 11:passive zabbix agent的連接過程,並沒有第十一步的數據報!當第十步中,server端確認連接關閉,並轉變狀態為closed之后, agent會把TIME_WAIT掛起兩分鍾。 這意味着這個連接在兩分鍾內是不可重用的。
注意:
使用TCP協議,是為了在不可靠的網絡環境中創建可靠的連接!
zabbix並不支持UDP和長連接的方式(persistent connection)
四、解決方式
設置TIME_WAIT的重用
linux服務器,配置內核參數中的 net.ipv4.tcp_tw_recycle
/etc/sysctl.conf 添加下面的3行,然后執行sysctl -p [root@ns_xxx.xx..161.182 ~]$ tail -4 /etc/sysctl.conf # tcp連接保持時間為1800秒 net.ipv4.tcp_keepalive_time = 1800 # 回收TIME_WAIT占用的連接 net.ipv4.tcp_tw_recycle = 1 [root@ns_xxx.xx..161.182 ~]$ sysctl -p net.ipv4.ip_forward = 0 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.default.accept_source_route = 0 kernel.sysrq = 0 kernel.core_uses_pid = 1 net.ipv4.tcp_syncookies = 1 kernel.msgmnb = 65536 kernel.msgmax = 65536 kernel.shmmax = 17179869184 kernel.shmall = 4194304 kernel.shmmni = 4096 fs.file-max = 655350 kernel.sem = 250 32000 128 1024 net.ipv4.tcp_keepalive_time = 1800 net.ipv4.tcp_tw_recycle = 1 [root@ns_xxx.xx..161.182 ~]$ netstat -an |grep -i time|grep 10050|grep -v 5432|wc -l 0 # 現在TIME_WAIT為0個,原先有89個
注意:
關於tcp_tw_recycle:
如果是tcp_tw_recycle被打開了話,會假設對端開啟了tcp_timestamps,然后會去比較時間戳,如果時間戳變大了,就可以重用。但是,如果對端是一個NAT網絡的話(如:一個公司只用一個IP出公網)或是對端的IP被另一台重用了,這個事就復雜了。建鏈接的SYN可能就被直接丟掉了(你可能會看到connection time out的錯誤
