基於消息隊列實現分布式事務
場景:
訂單系統產生訂單,購物車系統減購物車中的商。
實現思路 :
- 訂單系統在消息隊列上開啟一個事務(沒有創建訂單)。
- 訂單系統給消息服務器發送一個“半消息”,這個半消息不是說消息內容不完整,它包含的內容就是完整的消息內容,半消息和普通消息的唯一區別是,在事務提交之前,對於消費者來說,這個消息是不可見的。
- 半消息發送成功后,訂單系統就可以執行本地事務了,在訂單庫中創建一條訂單記錄,並提交訂單庫的數據庫事務。
- 然后根據本地事務的執行結果決定提交或者回滾事務消息。如果訂單創建成功,那就提交事務消息,購物車系統就可以消費到這條消息繼續后續的流程。如果訂單創建失敗,那就回滾事務消息,購物車系統就不會收到這條消息。
橙色和綠色分別是兩個事務。
問題:
步驟4事務提交失敗;這時候訂單系統本地事務已提交爾購物車系統沒有收到消息,造成數據不一致。
如何解決消息隊列事務提交過程出現的異常:
kafka會直接拋出異常用戶自行處理;
在RocketMQ中的事務實現中,增加了事務反查的機制來解決事務消息提交失敗的問題 , RocketMQ的Broker沒有收到提交或者回滾的請求,Broker會定期去producer上反查這個事務對應的本地事務的狀態,然后根據反查結果決定提交或者回滾這個事務。
為了支持事務反查機制,我們的業務代碼需要實現一個反查本地事務狀態的接口告知RocketMQ本地事務是成功還是失敗。
本例中的反查邏輯很簡單只需根據消息中的訂單ID,在訂單庫中查詢訂單是否存在即可。
能不能在訂單創建完成后再向消息隊列發送訂單數據?這樣不用考慮訂單創建失敗而發送消息的情況了
考慮這樣一種情況:訂單創建成功了,還沒來得及發消息,這個節點突然斷電了。
還有一種情況訂單創建成功,減購物車(后續操作)失敗的話要寫實物補償把創建的訂單刪掉。
能不能這樣:
1.開啟本地事務創建訂單,2.發消息,3.根據發消息是否成功來決定提交還是回滾本地事務。這樣不需要事務消息也能解決這個場景的問題了?
如果本地事務提交失敗已發送的消息無法撤回,會導致數據不一致。
小結
不論是消息隊列事務還是異步事務都遵循事務的四大特性:原子性,一致性,隔離性,持久性。
更多實現分布式事務的方法: https://blog.csdn.net/ityqing/article/details/102655827
**** 碼字不易如果對你有幫助請給個關注****
**** 愛技術愛生活 QQ群: 894109590****