交易環節訊息中介軟體設計——去哪兒餘昭輝
交易環節訊息中介軟體
問題考慮
不能丟訊息
丟訊息意味著掉單,意味著支付成功但是沒給人家出票,這是不能接受的。
穩定
訊息中介軟體一旦出問題,交易不能進行,也是嚴重的故障。
效能
典型的訊息中介軟體包含 3 部分
producer(釋出者)、broker(訊息中介軟體)、consumer(消費者),是一個比較簡單的模型,下圖展示了把訊息傳送給 consumer 的全過程。
Producer 釋出端設計
一致性、容災、效能
分散式事務一致性
上圖是一個訂票的訂單服務,生成的新訂單。
如果訂單持久化成功(上面的紅框 ),訊息傳送失敗( 下面的紅框 )。那麼使用者看到下單成功,假設代理商服務訂閱這個訊息是否給使用者出票,那麼現在的情況就是票沒出來,這會引起使用者投訴。
但是如果先發訊息,然後再持久化訂單,那可能就是訂單出票了,但其實這個訂單還沒下呢,這就會造成公司的損失。
解決方法一:
多個庫的操作是可以放在同一個事務裡
-
開啟事務。
-
業務操作,比如說訂單進行持久化等等動作。
-
生成訊息,並持久化,這和業務操作是在同一個事務裡。
-
事務提交。
訊息真正發到出去。訊息如果傳送成功了,會將訊息表裡的訊息刪除,而此時如果訊息傳送失敗了,後臺有一個任務會把訊息表裡面傳送失敗的訊息重新進行傳送,這樣最終達到一致性,保證業務操作成功了,訊息一定能發出去。
缺點
儲存成本。本來只有業務操作訪問 DB,然後還要持久化訊息。原來承受一個 QPS 現在可能只能承受一半了,所以對資料庫操作還是略重一些
呼叫了 RPC。這樣的動作是不能放在一個數據庫事務裡的,所以對於這種場景就不能滿足了
解決方法二
1.發新的訊息,直接發給 broker,這個訊息發給 broker 並不立即將訊息投遞出去。
做本地的操作
2.再調broker的介面,這一步真正把訊息傳送出去。
如果這個時候,即使第一步操作成功,第二步傳送失敗了,第一步傳送給 broker 的訊息就是一個未決狀態。
3.broker反過來詢問producer,那條訊息是發還是不發出去呢?這種模型就不需要一個將一個訊息庫放在業務庫同例項了,比較靈活,成本也更低些。但是業務使用的複雜度可能要高一些,需要提供一個介面供 broker 反查。
容錯
broker 會有不同的叢集,producer 發訊息有一個優先順序,預設訊息優先發到本機房叢集,本機房宕掉或者其他什麼原因不可用再向別的機房進行傳送。
隔離
Broker 訊息中介軟體設計
訊息中介軟體要支援非常多的 subject,全公司都在使用訊息中介軟體,各業務開發水平也參差不齊,如果有的系統弄了一個死迴圈,瘋狂的發訊息就會給系統帶來不可控的壓力,所以中間層需要做好隔離。其次,業務使用訊息中介軟體可能會遇到各種各樣的問題,需要輔助工具進行診斷。最後還需要全面的監控能力。
actor 這種模型,系統裡可以跑成千上萬的 actor,它肯定也有一個排程器,最後就模仿 akka 的排程器,它叫 dispatcher,實現了排程的策略。
可治理
如果這個時候訊息中介軟體出問題了,我們就可以根據上線時可靠級別給有的訊息降級。
降級也有很多種策略,比如
1.僅僅給投遞一次,如果中介軟體出問題,這種訊息就投遞一次算了,不管你是否消費成功,都不給你重發。
2.還有重發次數,比如有的消費者那邊有問題,消費不成功,比如消費格式變了,重發一天也消費不了,就可以實時的去調整訊息的重發次數。
3. 還有可以按多少比例給它發訊息,比如說 50%,那麼 50% 的訊息就給拋棄。
4. 日誌降級
比如訂單支付的訊息級別是最高的,但是搜尋,比如說現在有報價,代理商幫旗下所有的酒店價格變了一下,關心它的系統就要受到價格的更新,這是通過訊息廣播出去的。這個訊息,它的變動是比較頻繁,QPS 也很高,丟了一兩條訊息,可能又被後面的訊息覆蓋了,它的可靠級別就比訂單的級別要低,這個時候遇到問題,為了保護訂單訊息,肯定首先對它進行降級。
輔助工具
訊息的傳送投遞軌跡視覺化
訊息回溯。
比如消費者把訊息的內容理解錯了,幾號到幾號之間所有的訊息都要進行重新發送,這樣就要回溯這段時間的訊息。
訊息補發。
漏發的訊息,把訊息重新補發一下,使用者可以上傳一個檔案,將這些檔案裡的內容解析成訊息然後傳送。
顯示訊息的傳送和消費的關係。
系統發出了哪些 topic 的訊息,系統訂閱了哪些 topic 的訊息,有哪些消費有哪些訂閱了,這些都非常重要。
監控
監控分為兩塊。
一個是指標監控,比如像 QPS 監控,耗時等。可以細化到 subject、consumer 等粒度。
第二個是鏈路監控、全鏈路跟蹤,這是另外一個產品 QTracer 做的,可以根據訊息 id 來查這個訊息所關聯的鏈路,來看看這個訊息的情況。
Consumer 消費端設計
上下線控制
冪等
關於順序
順序訊息的實現
一種是狀態機。
涉及交易的系統一般都有狀態機。比如訂單流轉,假設現在訂單狀態是待支付,業務收到支付成功的訊息,訂單就流轉成支付成功,這個時候收到了訂單完成或者出票成功這樣的訊息,這個訊息不是對應的當前狀態,都會進行拒絕,拒絕後訊息的 server 稍後會重發。
另外一種方法是 producer 在訊息裡面攜帶一個版本號
Consumer收到以後會和自己當前的版本號進行比較,接到訊息的版本號如果小於資料庫的版本號,這個訊息就不消費了,直接吞掉,這裡要注意,這樣的訊息就不是拒絕了。