如图所示,bool withdraw(account_id, amount)函数表示:从account_id对应的账户中扣除amount数额的钱;如果扣除成功则返回true,账户余额减少amount;如果扣除失败则返回false,账户余额不变。
如果withdraw请求已经被服务器端正确处理,但服务器端的返回结果由于网络等原因被掉丢了,导致客户端无法得知处理结果。如果是在网页上,一些不恰当的设计可能会使用户认为上一次操作失败了,然后刷新页面,这就导致了withdraw被调用两次,账户也被多扣了一次钱。因此我们要做幂等控制。
问题:
如果采用采用分布式事务,通过引入支持分布式事务的中间件来保证withdraw功能的事务性,有哪些中间件可以提供这些功能?具体怎么实现的啊?
首先,RocketMQ 阿里開源的消息中間件,原來叫做MetaQ,文檔裡寫的是支持分散式事務的,因為RocketMQ的各個環節,包括生產者,消費者,broker都是分散式的,所以基本可以保障由於網路原因丟掉,不過我們在專案中並沒有使用這個特性.而且RocketMQ存在重複消費的問題,所以文檔明確表明了應該業務方自己實現冪等性.
其次,分散式事務我覺得大多數情況下,應該很少會有真的實現這個東西的.大多數情況下只要保證最終一致性就可以了,分佈式事務性能較低.
另外,冪等性和你說的分散式事務其實沒多大關係,同樣的場景,就算你的系統都在一起,如果接收到兩個相同的請求應該如何做?如果沒做到冪等性,不是分佈式場景下同樣會扣多.
而冪等性可以透過頒布token等(介紹的文章其實很多)實現
首先,這個場景和分散式的事務其實是沒有關係的!
其次,關於服務的冪等性問題,有多種保障方式,具體到你這個場景,可以在協定中定義一個請求表示requestID,在服務端,針對此requestID做驗證,例如採用簡單的redis分散式鎖或其他分散式鎖做冪等性驗證即可
涉及到失敗重試,所以提供方的接口必須是冪等的,但是諸如扣減庫存這種接口很難做到冪等,所以建議把失敗接口失敗重試關閉。
對於題主的這個場景,主要的原因是調用方因為超時失敗了,沒有對
amount
進行回滾,因為我猜的沒錯的話這應該是一個RPC調用吧,所以題主確實需要分佈式事務來執行事務回滾,具體可以參考ByteTCC用TCC的方式也是一種解決方案