讓研發人員緊張的這條「故障神經線」
- 2019 年 10 月 7 日
- 筆記

在眾多HTTP CODE 里,作為一名程式設計師我們都喜歡200,但從不喜歡以5xx打頭的HTTP返回碼,比如502,注意不是520。發生大量502報警,你會不會緊張,比如下面這張圖。平時為0,很短時間內達到3w+。

再比如,域名流量監控下,一旦洪峰流量過來,你會不會緊張。比如下圖所示,平時只有1、2百兆的流量,突然達到了2、3G的流量。

在同步應用下有一條「故障神經線」,一旦觸發就會讓你神經緊張。這條神經線是這麼建立的:用戶請求通過NGINX接入進來,首先抵達A系統,通過RPC的方式A系統去調用B系統。如下圖所示。

造成502最為常見的原因是故障依賴傳導,因為是同步調用,故障就會順著一層層的依賴關係反映到表層,正如上面這張調用鏈圖所示,從系統B傳導到系統A再通過VIP傳導到最終用戶。
形成這種「故障神經線」的原因,大致如下:
1、B系統變慢,可能原因是業務邏輯處理性能下降,也有可能是B系統依賴的資源出現性能問題。
2、A系統和B系統之間的網路出現問題,比如抖動、發生大量TCP重傳。
3、因為上述1和2的原因,A系統對B系統採取了容錯處理,比如限流、禁用,來防止故障擴大化。最要命的一點是,被限制了的請求發生重試,因為最外層的調用方一旦請求受限,他們可能會瘋狂的重試,造成流量洪峰,如上面第二張圖所示。
4、由於系統A做了容錯保護,比如執行緒池固定在了1000大小,那麼在這樣洪峰的情況下,因為重試處理不過來的請求,直接通過Nginx以大量502的HTTP狀態碼反映到用戶,如上面第一張圖所示。
這期間還有可能會造成如下問題:
1、分散式限流遭受熱點
一般我們實現分散式限流都是通過redis的方式解決。如果發生了某一個固定用戶且有很多台伺服器的瘋狂重試請求,因為單一的KEY的請求落到了一個redis集群分片上,就會觸發熱點。一般2C10G大小記憶體的一個分片,80000次/秒的請求,就會觸發我們事先設置好的熱點閾值了。
當上述這種分散式限流遇到瓶頸的時候,就需要考慮降級到單機伺服器限流,程式程式碼從本機的快取中讀取限流的配置資訊來進行限流的處理。
無論採用哪種限流方案都沒有好壞之分,只有符合自己業務場景的限流方案,而且能使用最小的成本來有效的解決技術上的難點,就是最好的方案。
2、TCP重傳次數過高
TCP是一種可靠的傳輸通訊協議,正是為了保證這樣的傳輸可靠性,有了重傳這樣的機制。它的原理是當發送一個報文後,會開啟一個超時重傳計時器 (Retransmission Timer , RTT),注意是計時不是計數器。如果在這個計時範圍內沒有收到來自目的接收方的確認,發送端就會啟動這樣的重傳機制。如下圖所示,就是TCP重傳監控的一個例子。

導致出現重傳的原因大致有如下幾種情況:
網路故障
如果兩個通訊服務端點之間發生了丟包、頻繁抖動等網路故障,如果網路品質不能較好的保障,根據TCP重傳機制的理解,從而出現TCP重傳的概率就會比較高。
伺服器埠SPEED設置不合理
兩台伺服器A和B,伺服器B為TCP傳輸的目標伺服器,此時如果伺服器A的埠速率speed是1000Mb/S,伺服器B的埠速率speed是10Mb/S,那麼因為目標伺服器的速率太小,則會造成TCP重傳。
請求速度遠遠大於響應速度
可能原因是接收請求處理的一方處理速度確實變慢,還有種可能是服務端處理的集群能力已經達到了極限。這兩種原因都會導致請求發送的一方觸發TCP重傳。
說回502
除了上面開始介紹的伺服器發生502的原因,還有其他原因可以造成502。比如防火牆阻止請求,因為某些DDos保護系統過度反應而阻止了系統的請求。網路發生錯誤,比如DNS問題,路由問題以及和ISP相關的問題等也可以導致502的發生。
但我們日常線上一旦發生大量502錯誤報警的時候,我們還是要首先排除服務系統的故障,502的本質原因,對於用戶來講就是訪問請求的響應超時造成的。
非同步能不能解決這種問題
一般RPC非同步模式都使用隊列或MAP來實現,然後用一個事件循環執行緒不停地輪詢隊列事件。這樣的模式下可以接收很多的請求並直接放入隊列,當有事件發生的時候,通過觸發回調函數來處理事件。由於使用的執行緒較少,切換開銷也少,也就基本不會有多執行緒阻塞的問題,如下圖所示。

上圖,及描述參考《架構修鍊之道》
還是以本文第三張調用圖為例來闡述,系統A通過非同步來調用系統B,對於系統A來講不需要等待,來了請求就直接調用到系統B,響應結果由事件循環發現處理並返回最終用戶。
那麼這樣會造成一個問題,如果請求量短時間內非常大對系統B就是一個衝擊,對系統A的記憶體隊列也是一個考驗。如果系統B遲遲仍然不能將最終要的響應結果返回的話,對於最終用戶這一端仍然是要發起重試。
所以非同步調用在短時間內大量請求過來的情況下也只是能緩解上述我們說的問題。
採用非同步調用可以大大減少調用方集群的伺服器數量,它能夠耗費很少量的資源去發起更多的請求,在大流量平穩調用下這是很好的處理方式,尤其是在網關應用中。
但極端流量請求下,如遇到分散式限流這樣的情況,也還是會遇到上面我們已經闡述的熱點問題。同事也還會遇到剛剛提到的記憶體問題,對下游的衝擊問題。但是,非同步在合適的場景下仍然是一個趨勢。
總結
一線研發人員不可能不跟線上問題打交道,會時長走在解決問題的路上,本文所講述的這條故障神經線,也是其中之一。我們從502現象開始說起,剖析了這條故障線的發生到表象,以及這個過程中觸發的問題點比如分散式限流熱點問題,TCP重傳問題。積累經驗,砥礪前行。