簡體   English   中英

如何在分布式系統中保持狀態一致

[英]How to keep state consistent across distributed systems

在構建分布式系統時,必須確保客戶端和服務器最終以一致的視圖結束它們正在操作的數據,即它們永遠不會失去同步。 需要格外小心,因為網絡不能被認為是可靠的。 換句話說,在網絡故障的情況下,客戶端永遠不知道操作是否成功,並且可能決定重試調用。

考慮一個微服務,它公開簡單的 CRUD API 和無限的客戶端集,由同一團隊、不同團隊和不同公司在內部維護。

在示例中,客戶端請求創建新實體,微服務成功創建並持久化該實體,但網絡出現故障且客戶端連接超時。 客戶端很可能會重試,在不知不覺中第二次持久化同一個實體。 這是我想出的一種可能的解決方案:

  • 使用客戶端生成的標識符來防止重復發布

這可能意味着主鍵,客戶端和服務器生成的組合鍵的一半,或服務發布的令牌。 服務要么持久化實體,要么在具有該標識符的實體已經存在的情況下回復 OK 消息。

但還有更多:如果客戶端在網絡故障后放棄(但實體被持久化),改變它的實體內部視圖,然后決定將它持久化到具有相同 id 的服務中,該怎么辦。 在這一點上,一般來說,服務只是默默地是合理的:

  • 使用客戶端發布的狀態更新現有實體

或者服務應該用一些關於發生了什么的更具體的狀態代碼來回答? 關鍵是,服務的開發人員無法真正影響客戶端設計解決方案。

那么,在網絡和系統故障的情況下,有哪些明智的做法可以保持分布式系統的狀態一致並避免最常見的陷阱?

您可以采取一些措施來最小化客戶端-服務器不同步情況的影響。

您可以采取的第一個措施是讓客戶端生成實體 ID ,例如通過使用 GUID。 這可以防止服務器在每次客戶端重試 CreateEntityCommand 時生成新實體。

此外,您可以使命令處理具有冪等性 這意味着如果服務器收到第二個 CreateEntityCommand,它只是默默地忽略它(即它不會拋出異常)。 這取決於每個用例; 某些命令不能成為冪等的(例如updateEntity )。

您可以做的另一件事是刪除重復命令 這意味着您發送到服務器的每個命令都必須用唯一的 ID 標記。 這也可以是 GUID。 當服務器收到一個帶有它已經處理過的 ID 的命令時,它會忽略它並給出肯定的響應(即200 ),可能包括一些關於命令已經被處理的事實的元信息。 命令去重可以放在堆棧的頂部,作為一個獨立的層,獨立於域(即在Application layer )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM