事務是將一次執行過程當中所涉及的全部操做歸入到一個不可分割的執行單元,組成事務的全部操做只有在全部操做均能正常執行的狀況下才能提交,只要其中任一操做執行失敗,都將致使整個事務的回滾。一句話來講,就是保證多個操做要麼都作,要麼都不作。同時一旦事務提交,則其所作的修改會永久保存到數據庫。html
基於衡量事務的四個特性,InnoDB 實現事務實際上就是 4 個特性的實現。java
原子性git
隔離性github
持久性sql
既然redo log也須要在事務提交時將日誌寫入磁盤,爲何它比直接將Buffer Pool中修改的數據寫入磁盤(即刷髒)要快呢?主要有如下兩方面的緣由:
(1)刷髒是隨機IO,由於每次修改的數據位置隨機,但寫redo log是追加操做,屬於順序IO。
(2)刷髒是以數據頁(Page)爲單位的,MySQL默認頁大小是16KB,一個Page上一個小修改都要整頁寫入;而redo log中只包含真正須要寫入的部分,無效IO大大減小。
一致性數據庫
現代軟件架構隨着業務領域劃分爲多個微服務,共同組成了複雜的軟件系統。而從數據庫層面來看,隨着數據量的爆發,不得不採用分庫分表的方式,下降數據庫的壓力。這樣,就形成多個服務依賴不一樣的數據庫,那麼在同時操做的時候,如何保證事務?這就是分佈式事務。緩存
簡而言之,分佈式事務就是一個大的事務由不一樣的子事務組成,這些小的事務操做分佈在不一樣的服務器節點上面,屬於不一樣的微服務,分佈式事務須要保證同一事務下的子事務要麼所有成功,要麼所有失敗,即保證數據的最終一致性。服務器
在這篇不想用太大的篇幅說一些概念上的東西,可是要說 RocketMQ 的分佈式事務實現,因此在這裏順便提一下當前分佈式事務的集中解決方案:架構
兩階段提交(2PC) 是 Oracle Tuxedo 系統提出的 XA 分佈式事務協議的其中一種實現方式,參考 《分佈式事務之兩階段提交(2PC)》 。併發
TCC 是基於嘗試、確認、取消來實現分佈式事務的,想了解更多,參考 《分佈式事務之補償事務( TCC )》 。
本地消息表 方案最初是ebay提出的,核心是將須要分佈式處理的任務經過消息日誌的方式來異步執行。消息日誌能夠存儲到本地文本、數據庫或消息隊列,再經過業務規則自動或人工發起重試。人工重試更多的是應用於支付場景,經過對帳系統對過後問題的處理。
除了上述外,還有一些解決方案,好比阿里 SEATA ,SAGA方案和最大努力通知...感興趣同窗們能夠自行了解,固然還有咱們這篇要說的 MQ 事務。
RocketMQ 是阿里開源的一款高性能、高吞吐量的分佈式消息中間件,基於消息異步方式提供了對分佈式事務的支持,實現事務最終一致性。
下面是 RocketMQ 事務消息的基本流程交互圖:
如圖其中分爲兩個流程:正常事務消息的發送及提交、事務消息的補償流程。
1.事務消息發送及提交:
(1) 發送 half 消息。
(2) 服務端響應消息寫入結果。
(3) 根據發送結果執行本地事務(若是寫入失敗,此時half消息對業務不可見,本地邏輯不執行)。
(4) 根據本地事務狀態執行 Commit 或者 Rollback( Commit 操做生成消息索引,消息對消費者可見)
流程圖以下:
2.補償流程:
(1) 對沒有 Commit/Rollback 的事務消息( pending 狀態的消息),從服務端發起一次「回查」
(2) Producer收到回查消息,檢查回查消息對應的本地事務的狀態
(3) 根據本地事務狀態,從新Commit或者Rollback
其中,補償階段使用定時器回查方式用於解決消息 Commit 或者 Rollback 發生超時或者失敗的狀況。
如上,小夥伴們應該對 RocketMQ 的事務消息有了必定的瞭解,下面看下如何在開發場景下如何使用。
發送事務消息時和普通的消息區別是,本身要新建一個 TransactionMQProducer
和對應的一個 TransactionListener
的實現。
this.producer = new TransactionMQProducer(config.getGroup()); this.producer.setNamesrvAddr(config.getNameServer()); this.producer.setExecutorService(config.getExecutorService()); this.producer.setTransactionListener(config.getTransactionListener());
TransactionListener
實現 TransactionListener
接口的兩個方法:
executeLocalTransaction(Message message, Object o)
checkLocalTransaction(MessageExt messageExt)
代碼詳見 👀 : https://github.com/wangning1018/rocketmq-transaction-message-demo
歡迎訪問 我的博客 獲取更多知識分享。