tcp_tw_recycle引發的間斷性服務無法訪問

問題描述:

外網雲服務器上部署了一個RabbitMQ節點,在公司內網調用RabbitMQ接口時經常返回以下錯誤:

panic: dial tcp 123.1.1.1:5672: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

訪問ECS上的HTTP服務,也出現了“響應時間過長”的現象,如下圖所示:

spacer.gif無法訪問網站.png

同時通過SSH連接雲服務器時,也返回了“Connection failed”錯誤。

這些問題持續不到1分鐘之後就又正常了。



分析過程:

1、懷疑網絡有丟包。

在又出現此問題時,分別在公司內網主機和雲服務器上執行mtr觀察。發現兩邊都沒有丟包現象,這個懷疑暫時排除掉了。mtr結果如下:

spacer.gif雲服務器mtr.png

內網mtr.png

spacer.gif

2、懷疑當時流量較高,帶寬被佔滿。

查看了監控端的流量圖表,發現流量曲線不穩定,有流量達到瓶頸的現象,於是在雲服務器上使用iftop命令(iftop -p)實時查看了流量情況。

當又出現問題時,流量也很平穩,這個懷疑點也被排除了。流量信息如下圖:

spacer.gif實時流量.png


3、懷疑當時的負載較高。

通過dstat實時查看負載,又出現問題時,各項指標都很正常。dstat部分結果如下:

spacer.gifdstat.png


4、懷疑是可使用的文件描述符達到了限制。

在雲服務器上查看之後,也排除了。結果如下圖:

spacer.gifulimit.png


5、會是防火牆drop了嗎?

雲服務器上運行的Docker啓用了iptables,除此之外沒有其他規則了。

spacer.gifiptables.png


6、查看sysctl.conf文件

文件中的幾個參數看起來沒有太大問題。

spacer.gifsysctl.png


7、考慮不同的網絡環境

把一個HTTP鏈接,發給了其他公司工作的同事。當問題又出現時,他在公司內部可以正常訪問,同時,我在手機上用4G也可以正常訪問。


8、ARP欺騙

能想到的原因都過了一遍,結論是“我公司網絡到雲服務器的網絡有問題”。最初想到了ARP欺騙。

查看雲服務器MAC地址:

[root@hadoop001 ~]# cat /sys/class/net/eth0/address

8.1、同時在公司內網主機和雲服務器上啓用tcpdump進行抓包。

其中,在雲服務器上執行的tcpdump命令如下(111開頭的地址是公司出口IP):

tcpdump -nn tcp port 15672 or tcp port 22 and host 111.*.*.* -w server.pcap

8.2、在問題出現時,我重複點了幾次RabbitMQ的Web管理控制頁面,並重試了幾次SSH。

8.3、用Wireshark打開下載pcap文件,對比了抓到的包中雲服務器的MAC地址和在服務器上拿到的MAC地址,結果是一樣的。


9、抓包結果中大量的RTO和亂序片段

RTO部分如圖:

spacer.gifRTO.png

結果說明:公司內網主機向雲服務器發送了SYN,但是雲服務器沒有返回ACK,內網主機在等待超時後重新發送了SYN。等待超時基於重新發送超時時間(RTO, retransmission timeout),在Wireshark中顯示爲“TCP Retransmission”。

亂序片段如圖:

spacer.gifooo.png

TCP Dup ACK:代表數據段丟失,重複ACK。圖中的[TCP Dup ACK 383#1]指數據段丟失的位置是383,爲第一次丟失。

TCP Out-Of-Order:收到的數據包亂序。


10、最後的分析

TCP Out-Of-Order和TCP Dup ACK,常見於網絡擁堵,延遲增大的情況下,後發送的數據包可能先到達。但是結合之前的mtr和iftop,表明公司內網主機和雲服務器之間不存在網絡擁堵的情況。

到這裏,事情已經明朗了,雲服務器上將內核參數“tcp_timestamps”置爲1,檢查客戶端每個數據包的時間戳是否遞增。當客戶端處在一個NAT環境時,共用同一個出口IP。因爲每個PC機上的時間不一定一致,不一定都準確。有可能導致從出口IP發往雲服務器的數據包,時間戳是混亂的,雲服務器檢查數據包時表現爲時間戳不是遞增的。

單獨啓用“tcp_timestamps”時,通常是沒有問題的,處於TIME_WAIT狀態的TCP連接等待2MSL之後,會被正常回收。而如果服務器同時將“tcp_tw_recycle”置爲1,就可能出現問題了。

將“tcp_tw_recyle”參數置爲1時,服務器會在一個小於2MSL的極短時間(2RTT)內回收處於TIME_WAIT狀態的TCP連接。由於已經釋放了socket,服務器無法用socket來標記一個連接,只能通過數據包中的時間戳來判斷是不是新的數據包,如果不是則丟棄。結果就是客戶端一直在重傳SYN,服務器不返回ACK。

11、處理方式

修改內核配置文件將以上內核參數值都修改爲0 :

vim /etc/sysctl.conf 
net.ipv4.tcp_tw_recycle=0 
net.ipv4.tcp_timestamps=0 
執行如下命令使修改的配置生效:
sysctl -p


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章