前言
上篇文章,王子通過一個小案例和小夥伴們一起分析了一下訊息是如何丟失的,但沒有提出具體的解決方案。
我們已經知道發生訊息丟失的原因大體上分為三個部分:
1.生產者傳送訊息到MQ這一過程導致訊息丟失
2.MQ自己發生故障導致訊息丟失
3.消費者拿到訊息後,由於操作不當導致訊息丟失
接下來我們就針對第一種情況,聊一聊如何解決生產者傳送訊息過程中的訊息丟失問題。
先傳送half訊息到MQ
針對於這一問題,RocketMQ是自帶一套解決方案的,就是事務訊息。今天我們就來看一下事務訊息的實現流程。
案例還是上次的案例,當使用者通過訂單系統下訂單支付的時候,在訂單支付成功後,會傳送訊息給MQ,但是這樣的流程是無法保證事務性的。
當我們引入事務訊息後,其實訂單系統是不會先去執行CRUD的操作的,而是先傳送一條half訊息給MQ,這個half訊息其實就是訂單完成支付的訊息,你可以理解為它的狀態是half狀態。
而積分系統是無法消費half狀態的訊息的。
訂單系統傳送了half訊息後就會等待MQ給出成功的響應,如下圖:
看到這裡有些小夥伴可能會問,為什麼要傳送half訊息呢?
其實大家可以想一下,假如我們不傳送half訊息,直接去運算元據庫,把訂單支付業務走完,然後再去傳送訊息給MQ,結果傳送過程中發生了異常,這就導致了積分系統無法消費到訊息,就會導致支付成功,而積分沒有發放的情況。
所以我們先發一條half訊息,就是為了先確認一下能否正常傳送訊息,或者說確認MQ是不是還活著,並且告訴MQ接下來的訊息很重要,不能丟失掉。
half訊息寫入失敗怎麼辦
half訊息的傳送也是可能失敗的,可能因為報錯、MQ自己掛了、或者網路原因導致訊息傳送失敗。
那訂單系統就會得到這一反饋,接著就應該進行回滾操作,比如訂單關閉,退款等操作。
half訊息寫入成功,並得到響應
那麼假如half訊息傳送成功,並得到了成功的響應後,訂單系統應該怎麼做呢?
這個時候,訂單系統就應該去運算元據庫,完成自己的業務功能了。
因為half訊息傳送成功,表示MQ可以正常接收訊息。
half訊息寫入成功,沒有得到響應
那麼假如half訊息傳送成功,但是沒有得到MQ的成功響應,會怎麼辦呢?
這個時候,half訊息已經正常的儲存到了MQ中,但訂單系統遲遲不能得到響應,可能會報一些網路超時的錯誤,訂單系統就去執行回滾操作了。
那麼對於這條half訊息該怎麼處理呢?
這就要說到RocketMQ的補償機制了,它會去掃描half訊息,如果這條half訊息遲遲沒有被rollback或者commit,一定時間後就會回撥訂單系統的一個補償介面,判斷一下這步操作是成功了還是失敗了。
如果成功了,那就重新傳送commit訊息給MQ,失敗了,重新傳送rollback訊息給MQ。後文會介紹rollback和commit訊息。
資料庫操作發生異常
那麼接下來如果訂單系統在執行資料庫的時候發生了異常怎麼辦呢?
這個時候資料庫本身是有事務機制的,同時我們再傳送一條rollback訊息給MQ就可以了。
這個時候MQ接收到rollback訊息後,就會把之前的half訊息給作廢掉了。
訂單業務完成後
那麼訂單系統自己的業務成功完成後接著做什麼呢?
這個時候就要傳送一條commit訊息給MQ了,讓MQ把之前的half訊息執行commit操作,之後積分系統就可以看到這條訊息了。
rollback或者commit訊息傳送失敗怎麼辦
rollback或者commit訊息也是可能傳送失敗的,這個時候其實也很簡單。
上文中我們已經說到了RocketMQ的補償機制,所以無論訂單系統本身是要傳送rollback訊息還是commit訊息,如果傳送失敗,MQ的補償機制就會掃描這條half訊息,一定時間之後回撥訂單系統的補償介面,判斷執行是否成功了,然後重新傳送訊息給MQ就可以了
總結
今天我們通過對RocketMQ傳送訊息這一過程進行各種情況的分析,會發現,開啟事務訊息流程後,生產者傳送訊息到MQ這一過程的訊息可靠性是可以得到保證的。
如果有小夥伴覺得有些情況還是沒有考慮到,歡迎評論區留言一起討論。
下篇文章我們將深入探索一下事務訊息的底層實現原理,歡迎小夥伴們圍觀。
往期文章推薦: