事務消息本質上解決的問題是業務系統與消息系統之間的事務問題(跨系統分佈式事務),其基本原理即兩階段提交以及最終一致性保障。最近看了下阿里雲mns事務消息的實現原理,介紹的蠻簡潔透徹的,對了解分佈式事務實現原理挺有幫助,在閱讀本文前推薦你們先仔細閱讀下阿里雲"mns事務消息"一文。php
事務消息
背景描述
有時候咱們須要實現本地操做和消息發送的事務一致性功能。即:消息發送成功,則本地操做成功;反之,若是消息發送失敗,本地操做失敗(成功也須要rollback)。保證不出現操做成功但消息發送失敗;或者操做失敗但消息發送成功的狀況;
另外,消費端,咱們也但願消息必定被成功處理一次,不會由於消息端程序崩潰而致使消息沒有成功處理,進而須要人工重置消費進度。html解決方案
利用消息服務MNS的延遲消息功能來實現。mysql
準備工做
建立兩個隊列:
1.事務消息隊列sql
消息的有效期小於消息延遲時間。即若是生產者不主動修改(提交)消息可見時間,消息對消費者不可見;2.操做日誌隊列網絡
記錄事務消息的操做記錄信息。消息延遲時間爲事務操做超時時間。日誌隊列中的消息確認(刪除)後將對消費者不可見。<!-- more -->分佈式
具體步驟
- 1.發送一條事務準備消息到事務消息隊列;
- 2.寫操做日誌信息到操做日誌隊列,日誌中包含步驟1消息的消息句柄;
- 3.執行本地事務操做;
- 4.若是步驟3成功,提交消息(消息對消費者可見);反之,回滾消息;
- 5.確認步驟2中的操做日誌(刪除該日誌消息);
- 6.步驟4後,消費者能夠接收到事務消息;
- 7.消費者處理消息;
- 8.消費者確認刪除消息;
以下圖:
異常分析:
生產者異常(例如:進程重啓):
A.讀取操做日誌隊列超時未確認日誌
B.檢查事務結果
C.若是檢查獲得事務已經成功,則提交消息(重複提交無反作用,同一句柄的消息只能成功提交一次)
D.確認操做日誌阿里雲消費者異常(例如:進程重啓):
消息服務提供至少保證消費一次的特性,只要步驟8不成功,消息在一段時間後能夠繼續可見,被當前消費者或者其餘消費者處理。spa
消息服務不可達(例如:斷網)
消息發送和接收處理狀態以及操做日誌都在消息服務端,消息服務自己具有高可靠和高可用的特色,因此只要網絡恢復,事務能夠繼續,能保證只要生產者:操做成功,則消費者必定可以拿到消息並處理成功;或操做失敗, 則消費者收不到消息的最終一致性。.net
原文地址日誌
這個過程須要注意到,咱們務必保證在preSendMessage沒獲得最終確認以前不被消費者獲取到,所以須要將發送的lifetime小於delaytime。
看到這裏也許你有疑問,爲何要將過程切分紅兩階段提交?咱們先假設若是採用一次提交的策略,很顯然此次提交的切入點只能存在於①本地事務開始以前②本地事務中③本地事務結束以後,那麼先看這三個切入點各自存在什麼問題。
」單次提交「遇到的主要問題是:沒法保障本地事務與消息被接受到的時序問題(或者說兩個分佈式事務的時序)以及數據的一致性問題。再回到」兩階段提交「,兩階段提交能解決這兩個問題嗎?兩階段提交的確認操做是在本地事務完成以後(這個相似於③),所以其可以解決時序問題,可是若是這個確認操做執行的過程當中發生了宕機等狀況致使確認操做失敗,依然會致使數據不一致問題。
mns經過延遲消息機制實現了兩階段提交,其如何保證數據一致性問題呢?通常咱們的策略都是經過操做流水來進行補償以達到數據的最終一致性,一樣的mns也是基於這個原理實現。
經過創建對opLog的監聽,咱們可以確保事務的最終一致性嗎?回答這個問題前,咱們先看這個問題的本質:最終、一致性。
最終一致性問題的產生是因爲發生了一些不可預期的問題,致使一個事務被提交(回滾),但消息沒被commit(rollback)。咱們經過opLog來追溯那些沒有獲得最終確認的消息並進行補償(最終),而且經過檢查本地事務的狀態來確認此次補償是commit或者是rollback(一致性)。正是基於這個補償的策略,mns事務消息解決了"兩階段提交"所遺留的一致性問題,但這個過程當中咱們須要注意幾個細節:
上面囉嗦的寫了一堆,看到這咱們不妨對思考下mns事務消息解決的是業務系統(本地事務)與消息中間件之間的事務協同問題,若是是兩個業務系統之間的分佈式事務如何實現?
好吧,若是堅持看到這,你可能以爲我標題黨了...那麼我建議你再讀一下」mns事務消息「一文。
更多文章請訪問個人博客轉載請註明出處