所有中間件都是為了解決特定領域的某個問題。
MsgBroker解決:分布式系統的消息傳遞的問題。
首先先了解消息中間件的一些背景知識
1.消息中間件
1.1消息中間件是什么
- 消息中間件用于分布式系統的消息傳遞
- 利用高效可靠的消息傳遞機制進行與平臺無關的數據交流
- 基于數據通信來進行分布式系統的集成
- 通過提供消息傳遞和消息排隊模型
1.2為什么要有消息中間件
原本的RPC接口調用有什么問題
- 客戶端服務進程和服務端服務進程的生命周期緊密耦合,緊密耦合帶來三個問題
- 客戶端進程和服務端進程必須都正常運行,如果由于服務方的對象錯誤或者網絡錯誤等引起的請求不可達,客戶端的請求就會異常。
- 后續客戶端有其他業務變更的時候服務端的服務也得做出相應調整。
- 同步處理導致服務端需要等待客戶端處理完后才能處理完,處理時間慢。
消息中間件解決了什么問題
- 客戶端和服務端的對象生命周期的松耦合關系:客戶端進程和服務端對象進程不要求都正常運行,如果由于服務對象崩潰或者網絡故障導致客戶的請求不可達,客戶不會接收到異常,消息中間件能保證消息不會丟失。
- 用異步通信模式:發送消息者可以在發送消息后進行其它的工作,不用等待接收者的回應,而接收者也不必在接到消息后立即對發送者的請求進行處理;
一個例子
一個賬單查詢Case,基本業務邏輯:
- 賬單服務:檢索數據庫,獲取指定賬戶的賬單記錄。
- 風險控制服務:記錄用戶的檢索行為,為風險控制提供數據積累。
- 短信通知服務:發送短信到用戶手機,通知用戶其賬單被查詢事件。
方案1,同步RPC調用
image
方案2,異步消息中間件
image
方案2對比方案1的優點:
- 賬單服務處理這個case時間減少了許多,提高了吞吐量
- 賬單服務,風險控制服務和短信通知服務完全解耦,后續有其他業務變更時,賬單服務不需要變更
- 風險控制服務和短信通知服務不可用時,不會導致賬單服務不可用
1.3消息中間件應用場景
- 系統集成:系統集成除了通過接口還可以通過消息。不同點:接口通過模塊間直接調用;使用消息中間件的系統通過消息模塊通信,通過消息來分解系統。
- 業務解耦:如果模塊之間不存在直接調用,那么修改或新增模塊對其他模塊影響最小。增加消息中間件后,業務模塊僅需關注自己的業務邏輯和如何將消息發送給消息服務器,消息由中間件存儲和分發。
- 異步處理:多個應用對消息中間件的同一消息處理,應用間并發處理消息,比起串行處理,減少處理時間。
- 改善系統性能(削峰填谷):比如上游系統的吞吐能力高于下游系統,在流量洪峰時可能會沖垮下游系統,消息中間件可以在流量高峰時堆積消息,而在峰值過去后下游系統慢慢消費消息解決流量洪峰的問題
- 跨平臺:跨平臺使用,降低網絡協議的復雜性
- 事務型消息:基于消息的通信是可靠的,消息不會丟失。可以發送事務性消息,而且大多數消息中間件都提供將消息持久化到磁盤的功能。
1.4消息中間件主要特點
- 可靠性:基于消息的通信是可靠的,大多數消息中間件都提供將消息持久化到磁盤的功能,可以發送離線消息,消息不會丟失。在分布式事務中擔當重要的角色。
- 異步:基于事件驅動架構,將調用異步化
- 分布式:消息中間件都是分布式的
1.5兩種模式
點對點模式 (point to point)
點對點模式下包括三個角色:
- 消息隊列
- 發送者 (生產者)
-
接收者(消費者)
image
消息發送者生產消息發送到queue中,然后消息接收者從queue中取出并且消費消息。消息被消費以后,queue中不再有存儲,所以消息接收者不可能消費到已經被消費的消息。
點對點模式特點:
- 每個消息只有一個接收者(Consumer)(即一旦被消費,消息就不再在消息隊列中);
- 發送者和接收者間沒有依賴性,發送者發送消息之后,不管有沒有接收者在運行,都不會影響到發送者下次發送消息;
- 接收者在成功接收消息之后需向隊列應答成功,以便消息隊列刪除當前接收的消息;
發布/訂閱模式(publish/subcribe)
發布/訂閱模式下包括三個角色:
- 角色主題(Topic)
- 發布者(Publisher)
- 訂閱者(Subscriber)
image
發布者將消息發送到Topic,系統將這些消息傳遞給多個訂閱者。
發布/訂閱模式特點:
- 每個消息可以有多個訂閱者;
- 發布者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須創建一個訂閱者之后,才能消費發布者的消息。
- 為了消費消息,訂閱者需要提前訂閱該角色主題,并保持在線運行;
1.6消費消息的推拉模式
- 推模式push:由消息中間件主動發消息給消費者
- 拉模式pull:消費者主動從消息中間件拉取消息
- 比較:采用push模式,可以盡可能快的把消息發給消費者,但是如果消費者處理一條消息能力較弱(處理時間長),消息中間件會不斷的發消息給消費者,到時消費者的緩存區溢出;采用pull模式,可能會增加消息的延遲。
1.7引入消息中間件需要注意點
- 復雜性:消息中間件都是分布式的,引入分布式會大大增加系統復雜度,在不同主機、不同進程之間的調用和調試,會帶來更多的不穩定性。分布式系統還會增加對外部系統的依賴。即使自己的系統沒有問題,也可能會因為依賴系統出問題而導致系統不穩定。
- 異步調用:帶來的業務交互的改變,有一定的操作延遲。
- 同步調用:盡管消息中間件也可用于同步調用,但這并不是它的長項,同步調用可以考慮使用HTTP、NIO等其他方式。
然后再看螞蟻的消息中間件msgbroker是怎么做的,重點講述MsgBroker的事務型消息
2.MsgBroker
2.1MsgBroker原理架構圖
image
2.2MsgBroker組成
- 消息發布者Publisher:發送消息的應用系統,發送消息到可靠消息組件 (MsgBroker)。
- 可靠消息組件MsgBroker:即MsgBroker,負責接收發布者發送的消息,根據消息類型和訂閱關系將消息分發投遞到一個或多個消息訂閱者。
- 消息訂閱者Subscriber:指訂閱消息的應用系統,收到的消息來自可靠消息組件 (MsgBroker)。
- 消息類型Message Type:一種消息類型由 TOPIC 和 EVENTCODE 唯一標識。
- 訂閱關系Binding:用來描述一種消息類型被訂閱者訂閱。
2.3Msgbroker特性
- 可靠性:MsgBroker確保消息可以投遞到訂閱者,發送者和訂閱者都不必擔心消息丟失
- 事務一致性:保證消息和本地數據庫事務的一致性
- 不保證消息不重復:所以訂閱者要做好冪等
- 不保證消息投遞順序:如果訂閱者有需求需要自己實現
2.4普通消息
普通消息:較簡單的發送和投遞兩個過程
image
2.5事務型消息
什么是事務型消息
一種特殊類型的消息:消息中間件收到消息發布者發布的消息后不會立刻投遞給消費者,而是根據發布者應用的數據庫事務狀態來決定是否投遞,如果數據庫事務是提交,就投遞;是回滾就不投遞。
為什么要設計事務型消息
為了保證在分布式系統中數據庫變更之間以及數據庫變更和業務處理保持事務一致性。
事務型消息如何保證數據一致性
事務型消息通過“二階段”來保證一致性
- 第一個階段:當發送端像發送普通消息一樣,將消息發送給Broker,Broker會將該條記錄保存在數據庫中,并將其事務狀態設置為未知狀態。 入庫操作完成后,Broker會向發送端返回一個消息確認的信息,一階段結束。
- 第二個階段:發送端的代碼包在事務模板中,當這個事務完結的時候,發送端會將本地事務的執行結果(提交/回滾)發送給Broker,Broker對結果做出判斷。提交則發送,回滾則不發送
思考
- 為什么發送消息要在事務操作之前?
- 如果Msgbroker一直收不到事務的執行結果狀態(提交/回滾)時要怎么辦?
- 第一個問題,如果順序反過來,先執行事務,事務執行完成提交后再發送消息,那么消息發送失敗就會導致本地事務回滾,這個肯定是不合理的,因為事務回滾比重發消息代價高很多
- 第二個問題,如果MsgBroker一直沒收到事務的執行結果,這個在分布式系統里屬于異常情況,也是有可能發生的,比如 說網絡異常等,而Msgbroker作為一個嚴謹的消息中間件也考慮到了這種異常情況,設計了“回查階段”,這個階段只會在事務“提交/回滾消息”失敗時才會被觸發。
總結
- 消息中間件MsgBroker事務型消息通過“二階段”消息實現
- 事務型消息是否投遞與本地事務狀態保持一致
- 事務型消息狀態回查是為了保證事務型消息的嚴謹性
事務型消息(事務成功時消息才提交):
image
事務型消息(事務回滾時不發送消息):
image
4.幾個消息隊列比較
電商、金融對事務型消息要求較高,因此MsgBroker重點在于支持事務型消息
MsgBroker | RocketMQ | ActiveMQ | RabbitMQ | KafKa | |
---|---|---|---|---|---|
所屬公司社區 | 螞蟻 | 阿里 | Apache | Mozilla | Apache |
開發語言 | Java | Java | Java | Relang | Scale&Java |
消息消費模式(pull/push) | push | 多協議,均支持 | 多協議,均支持 | 多協議,均支持 | pull |
數據可靠性 | 可靠 | 可靠,同步刷盤,同/異步復制 | 可靠,master/slave | 保證數據不丟,slave備份 | 可靠,replica機制,容錯容災 |
持久化能力 | DB | 磁盤文件 | 內存/文件/DB | DB / 文件 | 磁盤文件 |
是否有序 | 無序 | 有序 | 可以支持有序 | 一個Client才有序 | 多Client有序 |
事務型消息 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
負載均衡 | 支持 | 支持 | 支持 | 支持 | 支持 |
關鍵場景 | 事務,高可靠 | 高吞吐,高可靠 | 高擴展 | 高并發,高可靠 | 高吞吐,分布式 |
5.知識點回顧
從本地事務到分布式事務到消息隊列
5.1事務
事務:一系列指令的集合
滿足:ACID原則
- Automicity(原子性):操作這些指令,要么全部成功,要么全部失敗
- Consistency(一致性):事務執行使得數據庫從一個狀態到另一個狀態,但是對于整個數據的完整性保持一致
- Isolation(隔離性):在一個事務執行過程中,任何數據變更都只存在于這一個事務中,不會被外界感知,只有事務執行完成后,其他事務才能感知到這個事務引起的數據變更。
- Durability(持久性):事務正確完成后,它帶來的數據變更時永久的。
5.2本地事務
本地事務是在單個數據源上進行數據訪問和更新,資源由資源管理器本地管理
image
本地事務特點:
- 一次事務只連接一個支持事務的數據庫
- 事務的執行保證ACID原則
- 會用到數據庫鎖
5.3分布式事務
跨越多個數據源進行數據訪問和更新。
隨著業務變得復雜,一個單機應用的一個數據庫會被拆成多庫多表,一個應用也會被拆成多個應用,整個系統處于分布式的狀態,這個時候就需要保證分布式架構下的數據一致性。關于分布式事務在之后學習XTS中間件的時候再深入了解。