分布式事務 — 可靠消息最終一致性方案
大家好,我是狼王,一個愛打球的程序員
事務想必大家并不陌生,比如經常被人提起的ACID,但是為了后續的分布式事務的內容,我們先來聊聊 ACID,然后再介紹下什么是分布式事務,最后著重講下基于可靠消息的分布式事務解決方案。
什么是事務
嚴格意義上的事務應該是具備原子性、一致性、隔離性和持久性,簡稱 ACID。
- 原子性(Atomicity),可以理解為一個事務內的所有操作要么都執行,要么都不執行。
- 一致性(Consistency),可以理解為數據是滿足完整性約束的,也就是不會存在中間狀態的數據,比如你錢包有100,我錢包有100,你給我打50塊,此時你錢包的錢應該是50,我錢包的錢應該是150,不會存在我錢加了,你錢沒扣的中間狀態。
- 隔離性(Isolation),指的是多個事務并發執行的時候不會互相干擾,即一個事務內部的數據對于其他事務來說是隔離的。
- 持久性(Durability),指的是一個事務完成了之后數據就被永遠保存下來,之后的其他操作或故障都不會對事務的結果產生影響。
而通俗意義上事務就是為了使得一些更新操作要么都成功,要么都失敗。
什么是分布式事務
分布式事務顧名思義就是要在分布式系統中實現事務,它其實是由多個本地事務組合而成。
一次大的操作由不同的小操作組成的,這些小的操作分布在不同的服務器上,分布式事務需要保證這些小操作要么全部成功,要么全部失敗。從本質上來說,分布式事務就是為了保證不同數據庫的數據一致性。
常見的分布式事務的解決方案有以下幾種:2PC,3PC,TCC,本地消息表、可靠消息最終一致性、盡最大努力通知等
今天我們就著重講講可靠消息最終一致性的解決方案
什么是可靠消息最終一致性方案
可靠消息最終一致性方案是指當事務發起方執行完成本地事務后發出消息到消息中間件,事務參與方(消息消費者)一定能夠接收到消息并處理事務成功,此方案強調的是只要消息發給事務參與方,則最終事務要達到一致。
這個方式存在哪些問題?
此方案是通過消息中間件實現的,事務發起方(消息生產方)將消息發給消息中間件,事務參與方從消息中間件接收消息,由于網絡通信的不確定性會導致分布式事務問題,如下圖:
1.本地事務與消息的原子性問題
如上圖在虛線框內,存在以下幾種情況:
- 1)本地事務提交失敗,則消息不發送。
- 2)本地事務成功,消息發送失敗,本地事務回滾。
- 3)本地消息成功,消息超時,本地事務回滾,消息最終失敗。
- 4)本地消息成功,消息超時,本地事務回滾,消息最終成功。
綜上所述,存在第四種情況,造成本地事務,與消息參與方的事務不一致。
2.事務參與方接收消息的可靠性。
消息中間件與事務參與方要確保能夠成功消費到消息。
3.消息重復消費
注意事務參與方的接口冪等性問題,消息參與方可能已經成功消費,由于網絡問題導致消息中間件認為消息未消費,發起重試之后產生的問題。
解決方案
1.本地消息表
本地消息表的關鍵在于本地有一張存儲消息日志的記錄表,需要啟動一個定時任務去不停地掃描消息日志記錄,確保消息能夠被發送。具體流程如下圖:
上圖流程:
- 1)事務發起方本地事務執行成功,在本地消息表中記錄消息日志。
- 2)啟動定時任務,循環掃描本地消息表。
- 3)定時任務掃描到消息則發送消息到消息中間件。
- 4)消息中間件收到消息,成功返回消息發送成功通知給事務發起方。
- 5)事務發起方收到消息發送成功則刪除日志消息。
- 6)事務參與方訂閱消息,消費消息。
- 7)事務參與方處理本地事務。
- 8)本地事務處理成功,發送成功ack給消息中間件。
需要注意的點:
事務參與方保證接口冪等性。
2.RocketMq事務消息方案
Apache RocketMQ 4.3之后的版本正式支持事務消息,為分布式事務實現提供了便利性支持。在RocketMQ 4.3后實現了完整的事務消息,實際上其實是對本地消息表的一個封裝,將本地消息表移動到了MQ內部,解決 Producer 端的消息發送與本地事務執行的原子性問題。
實現流程:
- 1)事務發起方發送Half事務消息
- 2)RocketMq回復Half發送成功
- 3)事務發起方執行本地事務
- 4)事務發起方執行本地事務成功,發送commit到RocketMq,mq投遞消息到事務參與方;事務發起方執行本地事務失敗,發送rollback到RocketMq,mq刪除消息。
- 5)當RocketMq一定時間內未收到來自事務發起方的確認信息,會對事務發起方進行事務回查。
- 6)事務發起方查詢本地事務狀態。
- 7)事務發起方根據查詢到的事務狀態發送commint/rollback到RocketMq。
- 8)當RocketMq發起commit后,收到失敗或一定時間未收到成功ack,則會發起重試。
優點:
消息數據獨立存儲,降低業務系統與消息系統之間的耦合。
吞吐量優于本地消息表方案。
缺點:
一次消息發送需要兩次網絡請求(half消息 + commit/rollback)。
需要實現消息回查接口。
其實每種分布式事務的解決方案都有優劣,我們需要權衡利弊,選擇最合適業務場景的一種才是王道!
好了。今天就說到這了,我還會不斷分享自己的所學所想,希望我們一起走在成功的道路上!
本文轉載自微信公眾號「狼王編程」,可以通過以下二維碼關注。轉載本文請聯系狼王編程公眾號。