簡體   English   中英

使用 API 端點更新數據

[英]Updating data with API endpoints

假設有一個微服務,一個 API over http 有幾個端點,如:

  • 獲取賬戶余額
  • 將錢存入賬戶
  • 從賬戶中取款

現在假設有客戶端應用程序、子系統等向這個 API 發出請求。 例如:在 ATM 中,客戶可以取款,銀行 web 應用程序(前端應用程序)向 API 發出請求,第三方支付應用程序等外部應用程序等。

這是我正在考慮的場景:

  • 兩個應用程序/系統需要從同一個客戶賬戶中提取一些金額
  • app1 是一台 ATM,客戶要提取 $200
  • app2是一個支付系統,它需要為一些賬單提取100美元
  • 客戶余額為 250 美元

時間線: 1- app1 請求余額,api 返回 250 美元 2- app2 請求余額,api 返回 250 美元 3- app1 請求提取 $200 4- app2 請求提取 $100

如果 (3) 和 (4) 成功,此時余額可能小於 0。 假設在嘗試提取 API 之前檢查余額。 然后(3)將被允許,但(4)將返回錯誤。

1- app1 request balance, api returns $250 2- app2 request balance, api returns $250 3- app1 makes a request for withdraw $200 3.1- api get account balance (=$250) 3.2- $250 > $200 => withdraw allowed 4- app2 makes提款請求 $100 4.1- api 獲取賬戶余額 (=$50) 4.2- $50 < $100 => 不允許提款

好的。 但是,如果另一個應用程序/系統將 (3.1) 和 (3.2) 之間的余額從 250 美元更改為 150 美元怎么辦。 如果允許撤回,那顯然是不好的。

這是可能的情況嗎? 如何預防或避免?

這顯然不是微服務問題。 這也可能發生在 Monolith 應用程序中以及具有相同端點的情況下。

場景一:

  • 這更多是並發和事務的問題。

  • 並發問題可以通過鎖定悲觀或樂觀來解決。

  • 主要在 Web 應用場景或當前並發系統悲觀鎖水平不好。 在這種鎖定中,它將鎖定整行,直到一個客戶端為該帳戶完成操作。

  • 另一個是樂觀鎖定。

  • 對於您的方案,我們假設您有一個與帳戶行關聯的額外字段,其中包含帳戶余額。 此字段稱為 RowVersion(它可能由 DB 自動維護)

  • 現在假設您有系統 A 或系統 B(任何系統)

  • 當系統請求記錄余額時,它也會有這個rowversion。

  • 現在,當任何系統請求撤回時,在該請求中它具有此 RowVersion。

  • 當任何請求嘗試通過提款金額更新賬戶余額時,它也會檢查 RowVersion。

update account set balance = balance - requestwithdrawlamount where accountId = requestaccountId and rowversion = requestrowversion
  • 現在如果rowversion被其他系統改變了,那么這個操作將不會成功。

  • 如果 rowversion 沒有改變,那么更新成功並且 rowversion 自動更新到新的 rowversion (這個值主要由 DB 和原子方式控制)

  • 除了鎖之外,還需要考慮事務隔離級別。 它應該是可序列化的,以便為此類操作提供更好的一致性。

場景二:

在這種情況下,您可以使用一些消息傳遞系統。 需要確保對於特定的 accountId,所有消息都進入同一個分區。 通過這種方式,它將維持秩序。 這是異步操作並提供更多吞吐量。 在這種場景二中,您必須考慮鎖定和事務。 如果有兩個消費者在同一行上處理相同的消息,那么也會出現問題。 (主要避免使用分區,但仍然可以考慮用於金融系統)

最好使負責帳戶余額更改的所有方法同步,以便一個系統線程在執行自己的操作之前等待另一個系統線程完成其請求。

您應該有一個微服務負責此類事務。 由於所有余額驗證都發生在后端,所以你應該很好。 如果 app1、app2 和一些 3rd 方同時提款 - 他們將相互等待,因為他們在同一個賬戶上執行操作 + 檢查余額的方法 + 提款是同步的。

我相信並非所有的 PL 都具有進程同步之類的東西,所以我還推薦另一個選項,您基本上創建一些 object 保存有關 API 請求的信息,並且對於每個請求,您將這樣的 ZA8CFDE6331BD59EB2AC96F8911C4B66Z 放入隊列中(可以選擇根據配置提取第一個/最后一個記錄)。 然后,您配置一個線程,該線程將不斷輪詢隊列以獲取新記錄,如果有的話 -> 將 API 請求 object 傳遞到檢查帳戶余額並執行余額操作的方法中。

在這些選項中的任何一個中,如果帳戶余額小於請求提取的金額,您應該中止操作並向用戶返回錯誤。

暫無
暫無

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

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