擼明白分佈式事務(四)

前言

在分佈式系統中,消息隊列在服務端的架構中的地位非常重要,主要解決異步處理、系統解耦、流量削峯等場景。多個系統之間如果同步通信很容易造成阻塞,同時會將這些系統會耦合在一起。因此,引入了消息隊列,一方面解決了同步通信機制造成的阻塞,另一方面通過消息隊列進行業務解耦。簡單的服務間調用引入mq如下圖所示

可靠事件模式 

可靠事件模式,通過引入可靠的消息隊列,只要保證當前的可靠事件投遞並且消息隊列確保事件傳遞至少一次,那麼訂閱這個事件的消費者保證事件能夠在自己的業務內被消費即可。這裏,請讀者思考,是否只要引入了消息隊列就可以解決問題了呢?事實上,只是引入消息隊列並不能保證其最終的一致性,因爲分佈式部署環境下都是基於網絡進行通信,而網絡通信過程中,上下游可能因爲各種原因而導致消息丟失。

其一,主業務服務發送消息時可能因爲消息隊列無法使用而發生失敗。對於這種情況,我們可以讓主業務服務(生產者)發送消息,再進行業務調用來確保。一般的做法是,主業務服務將要發送的消息持久化到本地數據庫,設置標誌狀態爲“待發送”狀態,然後把消息發送給消息隊列,消息隊列收到消息後,也把消息持久化到其存儲服務中,但並不是立即向從業務服務(消費者)投遞消息,而是先向主業務服務(生產者)返回消息隊列的響應結果,然後主業務服務判斷響應結果執行之後的業務處理。如果響應失敗,則放棄之後的業務處理,設置本地的持久化消息標誌狀態爲“結束”狀態。否則,執行後續的業務處理,設置本地的持久化消息標誌狀態爲“已發送”狀態。

public void doServer(){
    // 發送消息
    send();
    // 執行業務
    exec();
    // 更新消息狀態
    updateMsg();
}

正反向消息機制

此外,消息隊列發生消息後,也可能從業務服務(消費者)宕機而無法消費。絕大多數消息中間件對於這種情況,例如 RabbitMQ、RocketMQ 等引入了 ACK 機制。注意的是,默認的情況下,採用自動應答,這種方式中消息隊列會發送消息後立即從消息隊列中刪除該消息。所以,爲了確保消息的可靠投遞,我們通過手動 ACK 方式,如果從業務服務(消費者)因宕機等原因沒有發送 ACK,消息隊列會將消息重新發送,保證消息的可靠性。從業務服務處理完相關業務後通過手動 ACK 通知消息隊列,消息隊列才從消息隊列中刪除該持久化消息。那麼,消息隊列如果一直重試失敗而無法投遞,就會出現消息主動丟棄的情況,我們需要如何解決呢?聰明的讀者可能已經發現,我們在上個步驟中,主業務服務已經將要發送的消息持久化到本地數據庫。因此,從業務服務消費成功後,它也會向消息隊列發送一個通知消息,此時它是一個消息的生產者。主業務服務(消費者)接收到消息後,最終把本地的持久化消息標誌狀態爲“完成”狀態。說到這裏,讀者應該可以理解到我們使用“正反向消息機制”確保了消息隊列可靠事件投遞。當然,補償機制也是必不可少的。定時任務會從數據庫掃描在一定時間內未完成的消息並重新投遞。

注意的是,因爲從業務服務可能收到消息處理超時或者服務宕機,以及網絡等原因導致而消息隊列收不到消息的處理結果,因此可靠事件投遞並且消息隊列確保事件傳遞至少一次。這裏,從業務服務(消費者)需要保證冪等性。如果從業務服務(消費者)沒有保證接口的冪等性,將會導致重複提交等異常場景。此外,我們也可以獨立消息服務,將消息服務獨立部署,根據不同的業務場景共用該消息服務,降低重複開發服務的成本。

瞭解了“可靠事件模式”的方法論後,現在我們來看一個真實的案例來加深理解。首先,當用戶發起退款後,自動化退款服務會收到一個退款的事件消息,此時,如果這筆退款符合自動化退款策略的話,自動化退款服務會先寫入本地數據庫持久化這筆退款快照,緊接着,發送一條執行退款的消息投遞到給消息隊列,消息隊列接受到消息後返回響應成功結果,那麼自動化退款服務就可以執行後續的業務邏輯。與此同時,消息隊列異步地把消息投遞給退款基礎服務,然後退款基礎服務執行自己業務相關的邏輯,執行失敗與否由退款基礎服務自我保證,如果執行成功則發送一條執行退款成功消息投遞到給消息隊列。最後,定時任務會從數據庫掃描在一定時間內未完成的消息並重新投遞。這裏,需要注意的是,自動化退款服務持久化的退款快照可以理解爲需要確保投遞成功的消息,由“正反向消息機制”和“定時任務”確保其成功投遞。此外,真正的退款出賬邏輯在退款基礎服務來保證,因此它要保證冪等性,及出賬邏輯的收斂。當出現執行失敗的狀態並且超過重試次數時,就說明這個任務永久失敗了,需要開發人員進行手工介入與排查問題。

總結一下,引入了消息隊列並不能保證可靠事件投遞,換句話說,由於網絡等各種原因而導致消息丟失不能保證其最終的一致性,因此,我們需要通過“正反向消息機制”確保了消息隊列可靠事件投遞,並且使用補償機制儘可能在一定時間內未完成的消息並重新投遞。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章