微服務調用超時處理
在開發過程中,應用程序通常會和其他的應用進行交互,應用系統之間的交互往往離不開網絡通信。然而,網絡環境是不穩定的,網絡超時是我們需要考慮的問題。
交互模式
-
同步
同步調用
同步調用接口返回兩種狀態,這兩種狀態都是終態,成功 S 或者失敗 F。同步調用會阻塞等待返回結果,如果長時間沒有結果返回則會等待超時。
-
異步
異步調用
異步調用會返回兩次結果,一次是同步返回一次異步返回。同步返回告知調用方請求已經受理,異步返回告訴調用方請求成功或失敗。
-
消息隊列
消息隊列交互
爲什麼要使用消息隊列?
-
接口異步化;
-
服務之間解藕;
-
消峯。
超時問題的解決方案
下面來分析在上面提到的三種交互模式中出現調用超時的情況,並提出相應的解決方案。我們將從兩個角度:服務調用方(客戶端)和服務提供方(服務端),分析出現超時,客戶端和服務端應該如何做。
同步超時
超時可能發生的點
同步調用超時發生的點
在同步調用的模式下,超時可能發生的節點有以下三處:
-
請求超時,客戶端給服務端發送請求時超時,此時服務端沒有收到客戶端的請求;
-
服務端內部超時,服務端可能存在 DB 操作、IO 操作、調用其他服務超時;
-
響應超時,服務端給客戶端返回響應時超時,此時服務端已經處理了請求。
客戶端
無論是何種超時,對於客戶端來說都是透明的,即客戶端無法知道具體發生超時的點。客戶端對於超時的處理,有如下兩種常見方法:
- 查詢,通過主動查詢去拉取超時請求的狀態。這種方法需要服務端提供查詢接口,並且是根據客戶端生成的請求流水號作爲查詢的條件,因爲同一個服務或者接口可能會存在多個調用方,這就需要服務端能夠唯一標識某一個客戶端請求。
如何唯一標識客戶端請求,有以下兩種方案可供參考.
全局流水號(traceId),全局流水號需要在所有調用方之間唯一,這可能需要在全公司層面有分佈式發號器的應用。
如果在調用方的應用有不屬於公司的應用,那麼全局流水號可能就不好控制了,這個時候可以使用:productId+productSeqId 的組合形式。productId 表示接入方的系統號,productSeqId 表示接入方的流水號,productSeqId 需要保證在同一個 productId 內是唯一的。這樣服務端就可以通過
productId + productSeqId
來唯一標識客戶端的請求。
- 重試,需要設置重試梯度(5s,30s,1min…),以及重試次數的閾值 (最多重試的次數)。另外,客戶端的重試需要服務端支持冪等(多次執行和只執行一次的效果一樣)。
服務端
對於①.請求超時
和③.響應超時
服務端是無法感知的,也就沒法進行處理。而在②.服務端內部超時
時服務端應該快速失敗,立即響應客戶端。如果是服務端調用其他服務 (例如,服務 C) 超時,服務端除了快速失敗之外,還需要調用服務 C 的衝正操作。
服務端內部調用其他服務超時
服務 C 的衝正接口需要能夠判斷之前是否接收過服務端超時的請求,如果接收過請求並做了處理,則應該執行反向的回滾操作,如果沒有接收過,則忽略衝正請求。
異步超時
超時可能發生的點
異步調用模式下超時發生的點
在異步調用的模式下,超時可能發生的節點有以下四處:
-
請求超時,客戶端給服務端發送請求時超時,此時服務端沒有收到客戶端的請求;
-
服務端內部超時,服務端可能存在 DB 操作、IO 操作、調用其他服務超時;
-
同步響應超時,服務端同步返回響應給客戶端超時,此時服務端已經接收了請求。
-
異步響應超時,服務端異步返回響應給客戶端超時,此時服務端已經處理完了請求。
客戶端
此時客戶端的處理方式和同步調用時客戶端的方式一樣。
服務端
服務端對於請求超時
和同步響應超時
無能爲力,不過對於異步響應超時
、服務端內部超時
是可以處理的,具體如下:
對於異步通知超時
可以採用最大努力通知
,服務端要求客戶端在收到異步通知時明確迴應服務端接收成功,如果服務端沒有收到客戶端的迴應,服務端重發異步結果。關於異步結果通知超時處理具體可以參考微信支付中的支付結果通知文檔
服務端內部超時
,我們應該盡最大努力使得用戶的請求處理成功。如果是服務端調用其他服務超時,可以通過查詢其他服務,根據查詢到的結果再進行後續的操作,並將最終的結果通過異步通知反饋給客戶端。
消息隊列超時
# 超時可能發生的點
消息隊列模式下超時發生的點
在消息隊列模式下,超時可能發生的點有兩處:
-
生產者投遞消息超時,對應上圖的①,②;
-
消費者消費消息超時。
生產者超時
生產者超時一般都採用可靠消息服務來解決,具體請參考後續的文章。
消費者超時
一般在開發過程中,基本上都可以認爲只要生產者將消息投遞到了 MQ 中間件的服務端,那麼該消息就一定會被消費者所消費,這主要是基於對消息中間件的信賴。一般而言,各大 MQ 中間件都有一定的機制來保障其到消費者之間的消息不會丟失。
不同 MQ 中間件的消費者機制有所不同,大概可以概括成以下兩類:
-
一旦消費者從消息中間件取走消息(無論是推模式或者拉模式都一樣),不管消費者是否成功處理,消息中間件都會將該條消息刪除;
-
消費者從消息中間件取走消息之後,消息中間件不會立馬將該消息刪除,必須要等到消費者告知消息中間件已經處理完了該消息後,消息中間件纔會將消息進行刪除。
所以在使用消息中間件的時候,我們必須得清楚這個消息中間件產品,它消息消費的具體邏輯是怎樣的。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/lDqM4ux-tnLrrvIreSn-yQ