文章目錄
- 復習昨日內容
- 為什么要使用消息隊列
- 為什么選擇 RocketMQ
- RocketMQ 的優缺點?
- 談談你對 RocketMQ 的理解?
- 消息隊列有哪些類型?
- RocketMQ 采用哪種消息隊列模型?
- 消息的消費模式了解嗎?
- 了解 RocketMQ 的基本架構嗎?
- 詳細解釋一下 RocketMQ 基本架構中四個構成部分的作用?
- 學習 RocketMQ Day2:進階(一)
- 如何保證消息的可用性/可靠性/不丟失呢?
- 如何處理消息重復的問題呢?
復習昨日內容
為什么要使用消息隊列
消息隊列是大規模分布式系統中非常常用的一項中間件技術,它的具體應用場景有:確保可靠性、服務解耦、消息異步、削峰填谷。
解耦
在分布式系統中,服務提供方可以作為生產者將服務響應打包為消息事件,發送到消息隊列當中,服務需求方從消息隊列中消費事件,這樣可以完成服務上下游的解耦,避免服務調用鏈上的某一環出錯而導致服務雪崩。
消息異步
系統中耗時的工作可以打包為消息事件并放到 MQ 當中,由消費者異步消費事件,發送到 MQ 之后可以快速響應用戶請求。比較典型的消息異步例子是:用戶新建訂單后,將商品服務和庫存服務的調用交由 MQ 異步處理。
削峰
削峰是 MQ 尤其是 RocketMQ 最典型的應用場景。通過 MQ,可以將瞬時的高流量轉化為持續的中低等流量,從而保護系統不被瞬時高流量沖垮。具體來說,大量用戶請求到達系統后,將用戶請求打包為消息事件交由 MQ,并快速響應用戶請求。MQ 中的消息按順序排隊,從而達到削峰的效果。
為什么選擇 RocketMQ
RocketMQ 具有低延遲、高吞吐量、高可用性等特點,非常適用于并發量大、實時性要求高的場景。
RocketMQ 的優缺點?
優點
- 單機吞吐量:十萬級;
- 可用性:非常高,基于分布式架構,方便拓展;
- 消息可靠性:經過參數優化配置,可以做到 0 丟失;
- RocketMQ 支持 10 億級別的消息堆積,不會因為消息堆積導致性能下降;
- 阿里出品,經過雙十一等多輪電商場景的考驗,穩定性值得信賴。
缺點
- 基于 Java 開發,對其他客戶端的支持性較差;
- 系統遷移需要大量代碼。
談談你對 RocketMQ 的理解?
RocketMQ 是一款可靠性強,可用性高,適用于并發量高,吞吐量大場景的消息隊列中間件,主要由 NameServer、Broker、Producer 和 Consumer 四部分組成。
RocketMQ 的優勢在于低毫秒延遲、億級消息堆積能力、事務消息和順序消息支持,通過主從結構、數據分片和零拷貝技術保障高吞吐和可靠性,尤其適合電商和金融交易這類高吞吐以及強一致的場景。
對比 Kafka,RocketMQ 支持事務且實時性更好;對比 RabbitMQ,RocketMQ 勝在分布式拓展能力以及海量消息的處理能力。
消息隊列有哪些類型?
消息隊列可以分為隊列模型和發布-訂閱模型。
隊列模型指的就是 Producer 將消息放在隊列當中,由 Consumer 進行消費。一旦 Consumer Group 中有一個 Consumer 將消息消費了,那么這個消息就不存在了,消費者之間是競爭關系。隊列模型較為簡單,是最基本的 MQ 模型。
發布-訂閱模型中進一步引入了發布者(Publiser)、訂閱者(Subscriber)以及主題(Topic)這三個概念。發布者負責生產和發送消息,它不直接將消息發送給訂閱者,而是發送給消息隊列組件;訂閱者會接收所訂閱主題的所有消息;主題是消息的分類或通道,發布者將消息發送到特定主題,訂閱者從特定的主題接收消息。
發布-訂閱模型的工作原理可以概括為:訂閱者向消息系統注冊一個或多個感興趣的主題,發布者將消息發送到特定主題,消息系統負責將消息傳遞給所有訂閱了該主題的訂閱者,每個訂閱者獨立接收消息,彼此之間互不影響,也就是說一份消息可以被多次消費。
RocketMQ 采用哪種消息隊列模型?
RocketMQ 采用發布-訂閱模型。
RocketMQ 的消息模型在邏輯上包含多個核心組件,它們的協同工作構成了完整的消息系統。具體來說:
1. 基礎消息單元:由 Message 以及 Message 的 Tag 構成。
- Message:消息傳輸的最小單位;
- Tag:Message 的二級分類(可以不指定 Tag),比如可以將一條發送給 Trade Topic 的 Message 進一步細分為 Payment / Refund …
2. 消息組織單元
- Topic(主題):消息的一級分類,是消息的邏輯通道。生產者在發送消息時,必須指定消息的 Topic。同時,Topic 也是消費者訂閱的基本單位。
- Queue(隊列):Queue 是消息實際存放的物理存儲分片,每個 Topic 默認包含 4 個 Queue。生產者向 Topic 寫入消息時,消息會均勻分布到某個 Queue,即** Message 會通過某種調度策略落到單個 Queue 當中**。Queue 是實現并行消費和水平拓展的基礎。
3. 消費相關組件
- Consumer Group(消費者組):消費者組是一組行為相同的消費者的邏輯集合。消費者組的消費模式有兩種,分別是集群模式和廣播模式。不同消費者組獨立消費進度。
- Producer Group(生產者組):生產者組是一組行為相同的生產者。
4. 消費位置管理
- Offset(偏移量):標識消費者在 Queue 當中的消費進度。
消息的消費模式了解嗎?
消息消費模式有兩種:集群模式和廣播模式。
默認情況下,消費者組采用集群消費,也就是一個消費者組當中的消費者競爭的消費 Topic 下的一條消息,一旦一條消息被消費過了,就不能重復消費了。
廣播消費模式指的是 Topic 下的每一份消息都會發送給消費者組當中的每一個消費者消費一次。
了解 RocketMQ 的基本架構嗎?
RocketMQ 的基本架構分為四部分,分別是 NameServer、Broker、Consumer 和 Producer。四者都采用集群模式部署,方便在分布式系統中快速地拓展。
詳細解釋一下 RocketMQ 基本架構中四個構成部分的作用?
NameServer
NameServer 是無狀態(這里的「無狀態」指的是 NameServer 僅存儲最基本的路由元信息,所有數據的狀態都是臨時的,不會被持久化,而是僅存儲在內存當中)服務器,角色類似于 Kafka 中的 Zookeeper。它的特點如下:
- 每個 NameServer 節點相互獨立,無信息交互;
- NameServer 幾乎是無狀態的,通過部署多個節點來標識自己是一個偽集群。Producer 在發送消息時,會預先從 NameServer 得知自己要發送給的 Topic 的 Queue 位于哪個 Broker 上。Consumer 也會定時從 NameServer 獲取 Topic 的 Queue 所在的 Broker 信息。Broker 在啟動時,會將自己注冊到 NameServer 當中,并通過心跳機制確保存活,定時維護 Topic 信息到 NameServer。
- 「需要注意的是」:由于 NameServer 節點之間相互獨立,因此 Broker 啟動時以及心跳保活時,都需要將自己的狀態發送給所有 NameServer 并行地進行注冊。邏輯上來說,NameServer 集群當中的所有節點最終的狀態是一致的。
Broker
Broker 扮演消息存儲與中轉的角色。具體來說,Broker 的職責如下:
- 消息存儲:持久化消息數據;
- 消息路由:保存 Topic 與 Queue 的映射關系;
- 服務提供:響應 Producer 的寫入請求與 Consumer 的拉取請求;
- 高可用保障:通過主從架構實現數據冗余。
在 Broker 當中,真正存儲消息的是 CommitLog,而 ConsumeGroup 存儲消息的邏輯隊列索引,它標記的是消息在 CommitLog 中的位置,按 Topic 和 Queue 進行分組。
單個 Broker 與所有 NameServer 保持長連接,定時將 Topic 信息同步到 NameServer。
Producer
Producer 是 RocketMQ 中負責發送消息的客戶端組件,它是消息的源頭,將業務系統產生的消息發送到 Broker 服務器。具體來說,Producer 有三種消息發送的模式,分別是:
- 同步發送:等待 Broker 返回確認消息;
- 異步發送:通過回調函數處理發送消息的結果;
- 單項發送:不關心發送的結果。
Producer 會自動從 NameServer 獲取 Topic 的路由信息,從而將 Message 發送到 Topic 所在的 Broker 服務器,因此 Producer 只需要知道 NameServer 的服務地址即可。
Consumer
Consumer 是 RocketMQ 中負責接收消息的客戶端組件,它從 Broker 中根據 Topic 拉取消息交由業務線程處理,是消息隊列的最終目的地。
Consumer 有兩種主要的消費模式,分別是:
- 拉取(Pull)模式:主動從 Broker 拉取感興趣 Topic 的消息;
- 推送(Push)模式:Broker 推送消息給消費者(底層仍然是消費者主動拉取);
學習 RocketMQ Day2:進階(一)
如何保證消息的可用性/可靠性/不丟失呢?
消息的可靠性保障可以從:生產者、中間存儲、消費者三方面入手。
生產者
在生產階段,通過請求確認機制,來確保消息成功被存儲:
- 同步發送時:注意處理響應結果與異常。消息成功發送才算成功,如果響應失敗,則需要重試機制確保消息重新發送;
- 異步發送時:需要在回調函數中處理發送失敗的情況,同樣通過重試機制來確保消息重新發送;
- 如果發生響應超時,可以通過查詢日志的 API 來查看消息是否成功存儲到 Broker,如果失敗仍然需要重試。
中間存儲
存儲階段,可以通過配置可靠性優先的 Broker 來避免因故障宕機而造成的消息丟失:
- 消息只要持久化到了 CommitLog,即使 Broker 宕機,未經消費的消息也不會丟失;
- Broker 的刷盤機制:同步刷盤與異步刷盤。顯然同步刷盤更可靠。
- Broker 通過主從模式確保高可用;
消費者
在消費者保障消息可靠意味著需要消費者成功將消息消費。關鍵在于消費者在客戶端確認消息成功消費的時機,不應該在消息剛剛收到就確認消費,而應該在業務執行完畢時才確認消費。這樣可以確保業務執行失敗時可以重新消費消息。
如何處理消息重復的問題呢?
RocketMQ 可以確保消息一定投遞且不丟失,即有消息可靠性保障,但是 RocketMQ 不能確保消息不被重復消費。
避免重復消費的兩個手段是確保在業務端做好冪等性處理,或是進行消息去重。
冪等性指的就是多次相同的操作不會對系統產生副作用,顯然讀操作一定具備冪等性,難點在于如何確保寫操作具有冪等性,比如庫存系統如果收到重復的扣減庫存消息,如何避免庫存被重復扣減?
一個可選的確保冪等性的方式是,通過 MySQL 記錄一張表,比如對于電商系統,新建一個訂單表并使用唯一的 ID 對訂單進行標識,這個表應該具有一個訂單狀態,如果訂單的狀態是已支付,那么重復到來的消息就不應該再一次扣減庫存了。當然也可以在 Redis 緩存中設置標志位來達到類似的效果。