記一次線上 K8s Ingress 訪問故障排查,最後竟不是 Post 的鍋

網路通訊頻道發表於2022-11-08

具體現象

應用遷移至我們的PaaS平臺後會出現偶發性的502問題,錯誤見圖片:

相比於程式的請求量,錯誤肯定是比較少的,但是錯誤一直在發生,會影響呼叫方的程式碼,需要檢查下問題原因。

為啥我們只看到了POST請求

讀者肯定會說,你們 ELK 過濾欄位裡面寫的是POST,所以肯定只有POST請求,hah。其實不是這樣的,GET請求也會有502,只是Nginx會對GET請求進行重試,產生類似如下的日誌:

重試機制是Nginx預設的: proxynextupstream

因為GET方法會被認為是冪等的,所以當一個upstream出現502的時候,nginx會再次嘗試. 對於我們的問題,主要想確認為什麼有502,只看POST請求就足夠了,兩者的原因應該是一致的.

網路拓撲結構

網路請求流入叢集時,對於我們叢集的結構:

不要問為什麼有了 Ingress 還有 Nginx。這是歷史原因,有些工作暫時需要由 Nginx 承擔。

統計排查

基於我們對於Nginx和Ingress的錯誤請求統計,發現兩者中的502錯誤是想等的,說明問題一定是出現在 Ingress<=>uwsgi 之中。

抓包

這個並不是最先想到的方案,因為我們用了很多統計方法也沒總結出來規律,最後只能寄希望於抓包了…

該請求日誌如下:

抓包結果如下:

從抓包情況來看,當前的 TCP 連線被複用了,由於Ingress中使用了HTTP1.1協議,會在一次tcp連線中嘗試傳送第二個HTTP請求,但是uwsgi沒有支援http1.1,所以在第二個請求根本不會被處理,直接拒絕了。所以在Ingress看來,這個請求失敗了,因此返回了502. 由於GET請求會重試,但POST請求無法重試,所以訪問統計中出現了POST請求502的問題。

Ingress配置學習

Ingress中, 預設對upstream使用的http版本為1.1, 但是我們的uwsgi使用的是http-socket, 而非http11-socket, 我們Ingress中使用了與後端不同的協議, 出現了意料之外的502錯誤。

因為 Nginx 預設是1.0, 但是切換到Ingress中預設變成了1.1, 而我們沒有統一, 解決方案是強制指定Ingress中使用的http協議版本。

如果有大佬看到了,可以簡單講講 Ingress 會在什麼時候複用 http1.1 的連線, 以及為什麼 Ingress 不復用每一個連線,這樣問題會盡快的暴露,這些問題我沒有繼續深究了。畢竟你換個語言比如 Golang 就沒有這個問題了, 這個是 uwsgi 專屬錯誤。

總結

有關這個502問題的排查,我個人覺得,最後抓包一次性解決問題其實沒什麼特別的,抓了就能發現問題,不抓就發現不了。

我是希望給大家一個啟發,對於一整條鏈路,如何來排查故障:我們這裡既使用了Nginx,又使用了 Ingress,在排查時,需要首先檢查兩者的錯誤數量, 如果確認錯誤基本一致,那就說明錯誤與 Nginx 沒有關係,需要檢查 Ingress 上的錯誤,對於多箇中轉的請求,這樣的排查能比較快的確定鏈路的錯誤位置。

來自 “ https://corvo.myseu.cn/archives/ ”, 原文作者:小米粥;原文連結:https://corvo.myseu.cn/archives/,如有侵權,請聯絡管理員刪除。

相關文章