分佈式系統中接口調用如何保證順序性?

一般分佈式系統接口的調用,不用考慮順序性,但是某些特殊場景可能確實是需要嚴格的順序保證。

比如,你的系統訪問系統 A,先插入數據再刪除。假設現在倆個請求請求 A 系統時,落在不同機器上,可能插入請求因爲某些原因執行慢了一些,導致刪除請求先執行了,此時因爲沒數據所以沒有起作用,結果這個時候插入請求過來了,數據插入進去了,那就造成數據不一致了。

本來應該是 “先插入 -> 再刪除”,這條數據應該沒了,結果現在變成 “先刪除 -> 再插入”,數據還存在。

這就是分佈式系統一些很常見的問題。

圖 1 分佈式系統用戶多個請求

解決方案

首先呢,從你係統設計來看,能不要這種接口請求順序性的保證要求就不要,因爲一旦引入順序性保障,比如就會導致系統複雜度上升,帶來系統性能降低,熱點數據壓力過大等問題。

如果你一定要引入這樣的功能,也是有解決方案的。

如圖 1 所示,我們可以在系統 A 之前加入一個接入服務,來自同一個用戶的每個請求都帶一個 id,比如 orderId,接入服務可以根據 orderId 做 hash 取模,把相同取模結果的請求分發到同一臺機器上。

圖 2 接入服務分發請求

用戶發起了 3 個請求,接入服務對 orderId 取模後,請求按請求 1,請求 2,請求 3 的順序分發到了同一臺機器上。

但是這裏有一個問題,假如系統 A 裏是多線程的處理請求,那麼還是會導致亂序,所以系統 A 內部也需要搞一個內存隊列,使請求有序化。

圖 3 系統 A 的內存隊列

系統 A 內部創建多個內存隊列,基於同樣的機制,對 orderId 取模,取模後值相同的請求分發到同一個內存隊列。如圖 3 中的 3 個請求分發到了同一個內存隊列,每個內存隊列有一個線程去消費。

但是這樣引發的後續問題就很多,比如說要是某個訂單對應的請求特別多,造成某臺機器成熱點怎麼辦?解決這些問題又要開啓一連串的複雜技術方案。

所以能不能從其他角度考慮一些解決方案,比如一個訂單的插入和刪除操作,能不能合併成一個操作,或者是其它的方法,避免這種問題的產生。

總結:

上面的解決方案並不能 100% 保證接口請求的順序性,用戶發起的 3 次請求,可能由於網絡的原因,不是順序性的到達接入服務。比如用戶發起的是請求 1-> 請求 2-> 請求 3,到達接入服務的順序可能是請求 2-> 請求 1-> 請求 3。

同樣的道理,接入服務轉發請求到系統 A 的請求,也可能會亂序。

所以上述方案只能 99.99% 的保證接口請求順序性。

如果想 100% 的保證接口請求順序性,那麼就需要使用分佈式鎖了,有興趣的讀者,可以自行研究下如何落地。

此時用戶發起的請求,必須要帶上請求的順序號,如圖:

圖 3 請求帶順序號

系統中使用分佈式鎖這種很重的技術方案,對性能影響非常大,也會大大增加系統的複雜度,如果可以,儘量不要使用。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/sOU1GZwJPn72pU72leXWmg