2015-10-11 58 views
4

我有幾個不同的RESTful服務託管在使用不同DB的不同服務器上。我有幾個RESTful服務,它們在應該是一個事務單元的情況下調用上面的多個這樣的服務。如果這些RESTful服務中的任何一個出現故障,我們最終會遇到數據一致性問題是否有一種巧妙的架構方式來協調回滾?或者讓交易經理走上正軌?REST和事務回滾

作爲一個簡單的例子,RESTful服務1有一個POST請求,它可以將thingamajig的項目數減少1. RESTful服務2 POST一次付款。如果服務2出現故障,我們如何在沒有新的RESTful退款服務的情況下乾淨地實現服務1的回滾(如果這是必須的話)。我正在尋找針對上述問題的架構性答案,這與REST原則保持一致。

+0

不能使用DDD和最終一致性?這樣你就不需要回滾失敗,只需重試。我認爲這比在REST服務之上實現多階段提交更容易。 – inf3rno

+0

類似的問題:http://stackoverflow.com/a/3837376/607033 – inf3rno

回答

1

分佈式事務很複雜,需要每個參與系統支持回滾的概念。在你的服務中,他們每個人都必須支持某種形式的回滾。在分佈式系統中協調這樣的事情在同步的方式中可能並不實際或不可取。在這樣的情況下,你會希望異步回滾,並且系統最終將在未來的某個時間達到一致。顯然還有很多其他細節(超時,錯誤處理,重試等)。

有關最終一致性的更多詳細信息,請查看維基百科條目here

+0

雖然其他評論者提出了類似的建議,將2種不同的服務合併爲一個(這可能屬於2個團隊,爲不同的垂直/客戶服務)是不可行的。因爲這個答案更適合在多團隊企業環境中解決這個問題,所以我接受了這一點。 – cvam

0

基本上問題是您需要在環境(HTTP)中使用默認不是事務性的事務 - 在數據庫意義上(因爲HTTP中事務是成功的請求 - 響應週期)。

@leeor響應的內容完全正確,我想添加的是我如何從設計網站解決問題。

所以你需要一個端點,可能是/transactions。通過POST方法您添加一個新的交易(具有所有必要的細節),這是不可變的 - 創建後,您只能通過GET方法詢問其數據/狀態。什麼可以更新交易狀態/數據只是服務器本身。

在創建事務時(創建事務期間),應創建參與事務的每個資源的快照(稍後可能會反轉)。然後開始執行所有操作,並在任何失敗的情況下,應該顛倒所有的快照。你沒有提到任何技術,所以很難提供合理的建議。您需要確定的是全面的日誌記錄。

4

您的回答:https://stackoverflow.com/a/1390393/607033您不能使用事務,因爲通過REST客戶端維護客戶端狀態並且服務器維護資源狀態。所以如果你想要資源狀態由客戶端維護,那麼它不是REST,因爲它會違反stateless constraint。違反無狀態約束通常會導致較差的可伸縮性。在這種情況下,它將導致水平可伸縮性差,因爲您必須同步實例之間正在進行的事務。因此,請不要嘗試在REST服務之上構建多階段提交。

可能的解決方案:

  • 您可以立即一致性堅持只使用 一個Web服務,而不是兩個。通過數據庫,文件系統等資源,多階段提交是必要的。當你打破一個更大的REST服務並將這些資源的使用轉移到多個更小的REST服務時,如果你錯誤地分裂了,那麼就會出現問題。這是因爲其中一個REST服務將需要一個它無法訪問的資源,所以它必須使用另一個REST服務來訪問該資源。這將強制多階段提交代碼移至更高的抽象級別,達到REST服務級別。您可以通過合併這2個REST服務並將代碼移到它所屬的較低抽象級別來解決此問題。
  • 另一個解決方法是使用REST以提供最終一致性,以便您可以立即接受202,並且可以稍後處理接受的請求。如果您選擇此解決方案,則必須通過開發您的應用程序來了解REST服務並非始終保持同步。 OFC。此方法僅適用於內部REST服務,通過該服務您可以確定客戶端在REST服務不可用時會重試,因此如果您編寫並運行客戶端代碼。
  • 另一種可能是最醜陋的解決方法是將每個事務 作爲資源存儲,因此您可以進行POST提交和回滾。我認爲這種可能的解決方案是不可行的,因爲它會違反統一的接口約束。我們將使用 POST /transactions/ {resource: "/forums/12/messages/45", method: "PUT", data: "..."}POST /transactions/1/commit而不是例如 PUT /forums/12/messages/45