一、前言
分佈式事務詳解:https://hucheng.blog.csdn.net/article/details/102975855
分佈式事務,我們一般都是強調的最終一致性,而不是強一致性。
RocketMQ
分佈式事務執行流程圖:
RocketMQ事務消息中概念
Half(Prepare) Message
指的是暫不能投遞的消息,發送方已經將消息成功發送到了 MQ 服務端,但是服務端未收到生產者對該消息的二次確認,此時該消息被標記成“暫不能投遞”狀態,處於該種狀態下的消息即半消息。
消息回查
由於網絡閃斷、生產者應用重啓等原因,導致某條事務消息的二次確認丟失,MQ 服務端通過掃描發現某條消息長期處於“半消息”時,需要主動向消息生產者詢問該消息的最終狀態(Commit 或是 Rollback),該過程即消息回查。
事務消息狀態
TransactionStatus.CommitTransaction
:提交事務,它允許消費者消費消息。TransactionStatus.RollbackTransaction
:回滾事務,它代表消息將被刪除,不允許被消費。TransactionStatus.Unknown
:中間狀態,它代表需要檢查消息隊列來確認狀態。
二 、RoctetMQ事務消息實現分佈式事務
我們舉一個扣款的例子,在單體項目中,我們很容易的去控制以下流程的事務:
而後面變成分佈式架構後,數據庫也可能分庫分表,此時我們控制分佈式事務很大,那麼豈不是單體應用的響應速度大於分佈式系統?
這裏我們可以將大事務轉換爲本地事務+異步消息
這裏會存在一個問題,如何保證本地事務和異步消息的同時執行或者回滾?
RocketMQ
事務消息即可保證這點:
事務消息producer
的設置:
producer.setTransactionListener(new TransactionListener() {
/**
* 在該方法中執行本地事務
*/
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
String tag = msg.getTags();
//本地事務執行
if (StringUtils.equals("TransactionA", msg.getTags())) {
try{
//執行本地業務代碼
}catch(Exception e){
//本地業務代碼異常,則也不發送消息
return LocalTransactionState.COMMIT_MESSAGE;
}
}
return LocalTransactionState.COMMIT_MESSAGE;
}
/**
* 對狀態爲LocalTransactionState.UNKNOW會進行回查
*/
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
//這裏進行回查處理
return LocalTransactionState.COMMIT_MESSAGE;
}
});
//發送事務消息
SendResult result = producer.sendMessageInTransaction(msg, null);
三 、RoctetMQ事務消息的限制
- 事務消息不支持延時消息和批量消息
- 爲了避免單個消息被檢查太多次而導致半隊列消息累積,我們默認將單個消息的檢查次數限制爲15次,但是用戶可以通過
Broker
配置文件的transactionCheckMax
參數來修改此限制。如果已經檢查某條消息超過N次的話(N= transactioncheckmax
)則Broker
將丟棄此消息,並在默認情況下同時打印錯誤日誌。用戶可以通過重寫AbstractTransactionCheckListener
類來修改這個行爲。 - 事務消息將在
Broker
配置文件中的參數transactionMsgTimeout
這樣的特定時間長度之後被檢查。當發送事務消息時,用戶還可以通過設置用戶屬性CHECK_IMMUNITY_TIME_IN_SECONDS
來改變這個限制,該參數優先於transactionMsgTimeout
參數。 - 事務性消息可能不止一次被檢查或消費。
- 提交給用戶的目標主題消息可能會失敗,目前這依日誌的記錄而定。它的高可用性通過
RocketMQ
本身的高可用性機制來保證,如果希望確保事務消息不丟失、並且事務完整性得到保證,建議使用同步的雙重寫入機制。 - 事務消息的生產者
ID
不能與其他類型消息的生產者ID
共享。與其他類型的消息不同,事務消息允許反向查詢、MQ
服務器能通過它們的生產者ID
查詢到消費者。