注冊用戶即可下載全站資源 關注Java幫幫微信公眾號
 

柔性事務:可靠消息最終一致性

9
發表時間:2018-12-11 15:37

   消息發送一致性:是指產生消息的業務動作與消息發送的一致。也就是說,如果業務操作成功,那么由這個業務操作所產生的消息一定要成功投遞出去(一般是發送到kafkarocketmqrabbitmq等消息中間件中),否則就丟消息。

   柔性事務、可靠消息最終一致性、異步確保性

下面用偽代碼進行演示消息發送和投遞的不可靠性:

1、先進行數據庫操作,再發送消息

  1. public void test1(){

  2. //1 數據庫操作

  3. //2 發送MQ消息

  4. }

這種情況下無法保證數據庫操作與發送消息的一致性,因為可能數據庫操作成功,發送消息失敗

2、先發送消息,再操作數據庫

  1. public void test1(){

  2. //1 發送MQ消息

  3. //2 數據庫操作

  4. }

這種情況下無法保證數據庫操作與發送消息的一致性,因為可能發送消息成功,數據庫操作失敗

3、在數據庫事務中,先發送消息,后操作數據庫

  1. @Transactional

  2. public void test1(){

  3. //1 發送MQ消息

  4. //2 數據庫操作

  5. }

   這里使用spring 的@Transactional日本韩国三级aⅴ在线观看注解,方法里面的操作都在一個事務中。同樣無法保證一致性,因為發送消息成功了,數據庫操作失敗的情況下,數據庫操作是回滾了,但是MQ消息沒法進行回滾。

4、在數據庫事務中,先操作數據庫,后發送消息

  1. @Transactional

  2. public void test1(){

  3. //1 數據庫操作

  4. //2 發送MQ消息

  5. }

   這種情況下,貌似沒有問題,如果發送MQ消息失敗,拋出異常,事務一定會回滾(加上了@Transactional注解后,spring方法拋出異常后,會自動進行回滾)。

   這只是一個假象,因為發送MQ消息可能事實上已經成功,如果是響應超時導致的異常。這個時候,數據庫操作依然回滾,但是MQ消息實際上已經發送成功,導致不一致。

5、使用JTA事務管理器

   前面通過spring的@Transactional注解加在方法上,來開啟事務。其實有一個條件沒有明確的說出來,就是我們配置的事務管理器是DataSourceTransactionManager

   事實上,Spring還提供了另外一個分布式事務管理器JtaTransactionManager。這個是使用XA兩階段提交來保證事務的一致性。當然前提是,你的消息中間件是實現了JMS規范中事務消息相關API(回顧前面我們介紹JTA規范時,提到DB、MQ都只是資源管理器RM,對于事務管理器來說,二者是等價的)。

   因此如果你滿足了2個條件:1、使用JtaTransactionManager 2、DB、MQ分別實現了JDBC、JMS規范中規定的RM應該實現的兩階段提交的API,就可以保證消息發送的一致性。

   DB作為RM,一般都是支持兩階段提交的。不過,一些MQ中間件并不支持,所以你要找到支持兩階段提交的MQ中間件。另外,JtaTransactionManager只是一個代理,你需要提供一個真實的事務管理器(TM)實現。如前面提到了atomikos公司,就有這樣的產品。

   但是筆者依然不建議,這樣玩。因為XA兩階段提交性能低,我們使用消息中間件就是為了異步解耦,這種情況,雖然保證了一致性,但是響應時間卻大大增加,系統可用性降低。

   那么如何保證,數據庫操作和消息發送的一致性呢?


兩種方案:一種是基于MQ的事務消息,以下展示了RocketMQ的事務消息機制。

BE2326B0-FC19-4620-BD2E-D34A32B8A405.png

事務消息的邏輯,由發送端 Producer進行保證(消費端無需考慮)

   首先,發送一個事務消息,這個時候,RocketMQ將消息狀態標記為Prepared,注意此時這條消息消費者是無法消費到的。

   接著,執行業務代碼邏輯,可能是一個本地數據庫事務操作

   最后,確認發送消息,這個時候,RocketMQ將消息狀態標記為可消費,這個時候消費者,才能真正的保證消費到這條數據。

日本韩国三级aⅴ在线观看    如果確認消息發送失敗了怎么辦?RocketMQ會定期掃描消息集群中的事務消息,如果發現了Prepared消息,它會向消息發送端(生產者)確認。RocketMQ會根據發送端設置的策略來決定是回滾還是繼續發送確認消息。這樣就保證了消息發送與本地事務同時成功或同時失敗。

   如果消費失敗怎么辦?阿里提供給我們的解決方法是:人工解決。

   

   另外一種實現,并不是所有的mq都支持事務消息。也就是消息一旦發送到消息隊列中,消費者立馬就可以消費到。此時可以使用獨立消息服務、或者本地事務表。

ECEB0CD9-A61C-4ED9-98C1-CE02A9B658C3.png

   可以看到,其實就是將消息先發送到一個我們自己編寫的一個"獨立消息服務"應用中,剛開始處于prepare狀態,業務邏輯處理成功后,確認發送消息,這個時候"獨立消息服務"才會真正的把消息發送給消息隊列。消費者消費成功后,ack時,除了對消息隊列進行ack(圖中沒有畫出),對于獨立消息服務也要進行ack,"獨立消息服務"一般是把這條消息刪除。而定時掃描prepare狀態的消息,向消息發送端(生產者)確認的工作也由獨立消息服務來完成。

日本韩国三级aⅴ在线观看    對于"本地事務表",其實和"獨立消息服務"的作用類似,只不過"獨立消息服務"是需要獨立部署的,而"本地事務表"是將"獨立消息服務"的功能內嵌到應用中。


支付寶贊助-Java幫幫社區
微信贊助-Java幫幫社區
Java幫幫公眾號生態

Java幫幫公眾號生態

總有一款適合你

Java幫幫-微信公眾號

Java幫幫-微信公眾號

將分享做到極致

Python幫幫-公眾號

Python幫幫-公眾號

人工智能,爬蟲,學習教程

大數據驛站-微信公眾號

大數據驛站-微信公眾號

一起在數據中成長

九點編程-公眾號

九點編程-公眾號

深夜九點學編程

程序員生活志-公眾號

程序員生活志-公眾號

互聯網,職場,程序員那些事兒

Java幫幫學習群生態

Java幫幫學習群生態

總有一款能幫到你

Java學習群

Java學習群

與大牛一起交流

大數據學習群

大數據學習群

在數據中成長

九點編程學習群

九點編程學習群

深夜九點學編程

python學習群

python學習群

人工智能,爬蟲

測試學習群

測試學習群

感受測試的魅力

Java幫幫生態承諾

Java幫幫生態承諾

一直堅守,不負重望

初心
勤儉
誠信
正義
分享
合作品牌 非盈利生態-優質內容分享傳播者
關于我們
友鏈申請
友鏈交換:加幫主QQ2524138991 留言即可 24小時內答復  
全站內容非商業用途,內容來源于網友,并遵循 許可,如有異議請聯系客服。
會員登錄
獲取驗證碼
登錄
登錄
我的資料
留言
回到頂部