網絡抓包定位504 gateway timeout問題

這是一位同事寫的筆記,裡面用到一些抓包命令,感覺不錯,分享給大家

業務反應偶爾出現訪問比較慢,出現landing狀態,檢查業務發現有一定概率瀏覽器返回504 gateway timeout (504錯誤代表網關超時 (Gateway timeout),是指服務器作為網關或代理,但是沒有及時從上游服務器收到請求)。

整體的服務架構是lvs->nginx->golang,其中nginx和golang的服務不在同一臺機器。登錄nginx的服務器,在日誌中發現不少504的請求,golang服務超過60秒沒有應答:

網絡抓包定位504 gateway timeout問題

504的請求,golang服務超過60秒沒有應答

對日誌進行統計發現504比例比較常高,並且分散到各種接口上都有,對mysql,redis等服務檢查發現各項指標正常,因此初步排除了是某項業務導致的接口超時。懷疑是nginx服務器和golang服務器之間網絡原因造成的。在其他各個機房進行訪問測試,發現都有一定概率發生超時。

通過ss查看到超時時的鏈接一直處於syn-send的狀態,沒有收到ack應答報文:

網絡抓包定位504 gateway timeout問題

通過ss查看到超時時的鏈接一直處於syn-send的狀態,沒有收到ack應答報文


通過tcpdump也同樣觀察到只發送syn報文,但是一直沒收到ack報文。並且分別在超時的2s,4s,8s後進行超時重試,直至最終超時都沒有收到對應的ack應答。這裡有個疑問,大部分情況是不會出現這種情況,證明兩臺服務器的鏈路應該是有至少一條通路。為什麼在對syn報文進行重發的時候一直不成功。tcp協議中的兩個報文是完全可能從不同的路由發送到目的ip的,這是協議允許的。

網絡抓包定位504 gateway timeout問題

通過ping命令和mtr命令檢查到目的端口的網絡丟包情況,都沒有發現丟包。由於ping操作走的是icmp協議,工作在網絡層,而tcp協議是傳輸層協議。通過ping發現沒有丟包,只能證明兩個網絡連通是正常的,並不代表tcp的的報文也會正常,但能證明鏈路沒有問題。

網絡抓包定位504 gateway timeout問題

ping


網絡抓包定位504 gateway timeout問題

traceroute


在docker服務器中抓包發現確實沒有收到client的syn包,因此也就沒有了應答。懷疑是宿主機與容器之間出現問題。

聯繫容器服務的同事,讓他們協助抓取宿主機和容器服務的報文。在client機器上,我們可以看到一個seq為1174736498, ack為3190591930的請求後,重新發起了一個seq為1068498692的syn報文,之後一直沒有收到ack報文,進行多次重試後仍未收到應答。

網絡抓包定位504 gateway timeout問題

seq=1068498692的syn報文

宿主機上的抓包顯示最後一個報文的seq為1174736498

網絡抓包定位504 gateway timeout問題

wireshark


容器服務器上抓包顯示最後一個報文的seq也為1174736498

網絡抓包定位504 gateway timeout問題

wireshark

宿主機和容器都對沒有收到seq為1068498692的syn報文,基本排除了宿主機的問題。對宿主機中運行的其他docker服務進行測試,發現也存在相同的問題。因此懷疑報文是在路由中丟失,一直沒有到達宿主機。

通過traceroute 10.198.134.183 發現每次的路由結果都不一樣。而其他沒有這種現象的機器路由表則是穩定的。內網環境下網絡環境比較簡單,路由器狀態相對穩定,路由表應該相對固定才對,這種經常變得情況下應該是有問題。聯繫ops同事協助定位問題,最終確認是路由上的問題。由於有一臺交換機故障,導致有一定概率形成環路,導致報文無法送達。

網絡抓包定位504 gateway timeout問題

traceroute


tcp報文重發也一直收不到的疑惑也隨著ops的解答而得到解決。交換機配置的hash模式是根據五元組進行hash,由於重發還是同一個端口,導致重發的鏈路是固定不變的,一直使用之前的鏈路。重新發起請求時,使用了新的端口,就有一定概率使用另一條鏈路。而ping命令使用的是icmp協議,沒有端口的概念,因此一直是一條固定不變的鏈路。因此ping能證明兩臺服務器是連通的,但是不能證明tcp報文一定可以到達。


分享到:


相關文章: