以下文章來源于腦子進煎魚了 ,作者陳煎魚
“微服務的戰爭” 是一個關于微服務設計思考的系列題材,主要是針對在微服務化后所出現的一些矛盾/沖突點,不涉及具體某一個知識點深入。如果你有任何問題或建議,歡迎隨時交流。
在《微服務的戰爭:統一且標準化》中,經過好幾周與不同業務組不同事業部的跨部門討論后,終于把初始的標準化方案給定下來了。
大家歡快的使用起了內部的統一框架,瘋狂的創建起了新服務,沒隔多久服務調用鏈就變成了下圖:
服務間存在多次內部調用,服務 A =》服務 B =》服務 C =》服務D,而 服務 E =》 服務 B,服務 F =》服務 E,也就是存在著多個流量入口,且依賴相同的服務。
背景
服務與服務中,總存在業務服務,公共服務,基礎服務等類型。但在某一個夜晚,突然發現 BFF 調用后端服務開始逐漸不正常,客戶給你截圖反饋問題,你發現有點問題:
單從表現來看,你發現是 BFF 調用服務 A 極度緩慢,也不知道怎么了...正當以為是服務 A 出問題,想著萬能重啟一下時。你在日志平臺和鏈路追蹤系統一看,發現了大量的錯誤日志和緩慢,讓你略微震驚,一時間不知道從何下手。
這可怎么辦?
級聯故障和雪崩
實際上這是一次很經典的級聯故障,最終導致系統雪崩的情景再現。單從上述拓撲來看,問題點之一在于服務 B:
服務 B 本身作為服務 A 和服務 F 的兩個流量入口必經之處,想必至少是一個公共服務,但他也依賴了其他多個服務。因此若服務 C 和服務 D 其中一個有問題,在沒有熔斷措施的情況下,就出現級聯故障,系統逐漸崩盤,最后雪崩:
服務 D 所依賴的外部接口出現了故障,而他并沒有做任何的控制,因此擴散到了所有調用到他的服務,自然也就包含服務 B,因此最終出現系統雪崩。
這種最經典的是出現在默認 Go http client 調用沒有設置 Timeout,從而只要出現一次故障,就足矣讓記住這類 “坑”,畢竟崩的 ”慢“,錯誤日志還多。
解決方法
常見的方式是根據特定的規則/規律進行熔斷和降級,避免請求發生堆積:
- 超時時間控制。
- 慢調用比例。
- 錯誤比例。
- 自適應(例如:負載情況等)。
當然,這也只是壯士斷腕,后續措施還包含監控告警,通知對應的開發人員來處理。且需提前對被降級的模塊進行業務邏輯進行處理等等,這樣才能夠比較柔和且快速地度過這一次危機。
總結
在分布式應用中,級聯故障和雪崩是非常常見的,一些開發同學在模塊設計時可能并沒有意識到這塊的問題,在微服務化后會一個不留神就碰到,因為其調用鏈變得特別的長且多。因此建議配套設施和限流熔斷措施都應該及時跟上,否則面對一大堆的錯誤日志還是很無奈的。
同時,監控告警的建設也要做,因為在危機出現時,有一個 HTTP 調用的 P95/P99 告警出現,那就比較舒心了,直接 root cause。