消息中間件 零

消息中間件是什麼?

MOM Message-Orientd Middleware is software infrastructure focused on sending and receiving messages between distributed systems.
消息中間件就是在分佈式系統中發送和接收信息的軟件.

從定義知, 我們通常說的消息中間件指的是在分佈式系統中收發信息的工具. 這裏涉及到兩個關鍵詞, 分佈式系統和收發信息(線程間的消息通信工具不在本篇介紹範圍). 也就是說, MOM是爲了解決分佈式系統中某些需求而應運而生的, 下面我們來分析下MOM的使用場景.

爲什麼使用MOM

想象下這樣的場景, A系統執行pA操作, 該操作不依賴B系統, 但是B系統依賴pA, 需要知道pA每次的執行結果. 通常情況下, 我們可能會在pA執行之後遠程調用B系統, 那麼A系統本來不依賴B現在卻要等待B系統響應, 這樣顯然是合理的. 那麼優化下, 使用異步調用怎麼樣? 當然可以, 異步就不用等待B系統的響應. 但是還存一些問題: 雖然A系統不依賴B系統, 不用關心B系統執行結果, 但是B系統依賴A系統, 那麼A系統是否成功調用B系統對B系統就非常重要, 那麼誰來保證調用的成功性, 當然是A系統; 不, 張繡說我們用了非常NB的RPC框架, 瘋狂重試, 重試到天荒地老, 保證可以調用B系統, 那你贏了Orz, 在A系統不掛的情況下. 在pA執行成功後, 在調用時出現問題是很可能出現的, 那就需要這個NB的RPC框架擁有存儲信息的能力.
另一個問題, 現在C系統跟B系統同樣的情況, 需要接收pA結果, 我們當然可以上述那樣在pA執行後調用, 但是你看到後面排隊的Z系統了麼. 這難不倒劉秀, 劉秀有非常NB的代碼生成工具, 通過配置文件引入不同的實現類, 然後異步循環執行每個實現類, 至於實現類中如何實現, 需要各個系統提供, 我們可以以引用jar包的方式來引入不同的實現類(我想象的, 感覺能實現.).
總結下, 兩位秀兒是從不同方面想要解決A系統和依賴它的各個系統的耦合性問題, 張繡的思路還是比較正確的, 通過加一層處理邏輯, 剝離A系統和其他系統的關係, 那麼這個NB的PRC框架, 擁有可以收發信息, 並且可以存儲信息的工具就是MOM了. 而劉秀的處理只是在某些程度上減少了調用邏輯的代碼, 從根本上沒有解決系統之間的耦合性. 現在有了MOM, 劉秀就可以讓MOM去執行他的各種實現類了.

MOM的基本能力

所以MOM爲我們解決這樣的問題:在一個分佈式系統中, 多個系統依賴A系統, 但是A系統執行不依賴這些系統, 我們希望在不影響A系統執行的前提下, 將執行結果通知其他系統. 當依賴系統增加時, 不需要修改A系統的業務代碼.
使用MOM解決了A系統和其他系統的耦合性, 轉而與MOM耦合. 既然大家這麼信賴MOM, MOM就需要用實際行動回報大家. MOM的基本功能就是接收生產者(Producer P, 比如A系統)的消息(pA處理結果)並把消息傳遞給消費者(Consumer C, 比如B系統).
** P -> M -> C**
在這個過程中, MOM需要保證: 接收到生產者信息後, 保證消息送達消費者, 並被消費者成功消費. 也就是說, 只要Producer業務執行成功, Consumer就必須業務執行成功(可以延遲 但是最終要執行成功).
在這裏插入圖片描述

在這個過程中, 可能會出現如圖問題:
1 Producer執行業務成功後, 發送信息給MOM失敗;
2 MOM成功接收Producer消息, 但是在發送給Consumer之前由於各種原因, MOM掛掉了
3 MOM發送給Consumer失敗
4 MOM成功發送消息給Consumer, 但是Consumer執行業務失敗
以上出現任何問題, 都會造成消息不一致. 在瞭解目前主流MOM之前, 我們先自己嘗試下(找資料), 如何解決上述問題.

Producer成功發送信息到MOM

這個是在系統處理完業務之後, 發送信息後通知其他系統業務操作結果. 此時如果發送失敗會導致生產者數據和消費者數據不一致.所以我們要保證業務和發送信息的一致性, 由於這些操作都在本地事務中, 所以我們只需要獲取到發送信息後的結果, 就可以保證一致性, 所以MOM在接收到信息後需要發送一個確認收到的信息.

MOM在接收到信息後掛掉了

在MOM接收到信息後, 避免消息丟失, 當然要對消息持久化, 通過設置消息狀態來區分哪些信息已經消費, 哪些還沒有, 掛掉後通過狀態繼續發送還沒有消費的信息.
這裏有個問題, 儘管我們會對消息進行持久化, 但是也存在某個時刻, MOM接收到了信息, 還沒有進行持久化就掛掉了, 那麼這時候信息不就丟失了麼? 後面我們看看主流MOM是如何解決這個問題的.

MOM發送給Consumer失敗

MOM發送消息給Consumer, 但是一直沒有收到Consumer確認收到的信息, 那MOM只需要一直重試就好了.

Consumer執行失敗

與上面問題的區別是, 這次Consumer已經告訴MOM, 我已經收到信息了, 但是執行業務失敗, 爲了保證業務不丟失信息, 在執行前要先保存信息, 保存操作放在Consumer端顯然不合適, 這樣每個Consumer都需要自己實現一套保存邏輯, 所以保存信息還是有MOM來做. 像我們上面說的一樣, 只需要設置消息狀態爲"未消費", 後面重試就可以該問題.

通信圖

根據我們上述的方案, 修改通信圖如下
在這裏插入圖片描述

MOM應用級功能

只擁有上述基本功能的MOM只是個玩具, 完全無法在實際中使用, 在實際使用中, 除了基本功能的實現, 高可用性是非常重要的. 而且在上面講到的基礎能力中, 我們多次使用重試機制處理異常情況, 那麼這時候很容易出現重複消息的情況, 如何進行去除同樣是需要關注的. 下面我們再想想如何設計.

集羣

大部分的分佈式集羣結構都是由一個master node和多個普通node構成, master負責管理node, 不處理業務, node主要負責處理業務. 爲了高可用, 可以設計secondary master防止master掛掉, 或者根據各種NB的選舉算法從node中選出master.
集羣的話, 需要考慮node掛掉, 或者擴容的情況. 這兩種情況其實都是一個問題: 消息的重新分配, 無論是node掛掉還是增加新的node, 都需要將原來某個node下的信息重新分配給其他node. 所以爲了解決上述問題, 我們的消息必須增加一個字段, 用來標記該消息是屬於哪個node的, 然後根據某個分配算法(最簡單的輪詢)分發消息.

消息去重

爲了保證數據一致性, 我們使用了多次重試操作, 這樣就可能造成信息重複的問題, 重複消息一般來自兩個方面
1 Provider沒有MOM的響應信息, 會重複發送信息, 爲了避免MOM處理重複信息, 我們可以使用一個標識來唯一標記一條信息, 這樣在MOM接收到多條信息後就可以通過消息唯一標識去重;
2 MOM沒有收到Consumer響應會重試, 這樣Consumer可能會收到多條信息, 我們同樣可以按照Provider處理, 或者在開發的時候將Consumer業務處理做冪等, 這樣多次消費重複的消息不會影響業務數據, 但是可能會浪費資源(數據庫更新操作).

特殊場景功能

針對特殊場景, 需要MOM提供些額外的功能

消息順序性

一般情況下, 先發出去的信息會先處理, 但是通常由於網絡等外部因素不會保證一定是順序的, 而且每個Consumer只關心一條業務線的順序, 比如支付流程, 先處理訂單, 再支付, 這個順序需要保證, 否則支付永遠成功不了. 而不同的兩筆支付, 先處理哪個就無所謂了, 也就是說MOM要保證消息的局部順序性.
爲了保證局部順序性, 首先要標記消息爲一條業務線, 然後每個消息的順序, 還要區分每組信息(需要看看框架都是怎麼實現的).

消息級別

這個很好理解, 對於比較重要的信息, 需要優先處理

總結

本篇是對MOM的一個整體認識, 後面會分析主流MOM是如何實現的.
1 消息通信模型
2 集羣模式: 增刪node處理
3 消息去重
4 消息順序性
5 消息級別
6 其他
下一篇是RabbitMQ, 2020-01-09
終於水完了一篇~~

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