阿里二面:RocketMQ同一個消費組內(nèi)的消費者訂閱量不同tag,會有問題嗎?
面試官:同一個消費組內(nèi)的消費者,如果訂閱了相同的 topic,但是訂閱的 tag 不一樣,會有什么問題嗎?
我:會出現(xiàn)丟消息的情況。
面試官:能詳細說一說嗎?
我:RocketMQ 要求同一個消費組內(nèi)的消費者必須訂閱關(guān)系一致,如果訂閱關(guān)系不一致,會出現(xiàn)消息丟失的問題。
面試官:什么是訂閱關(guān)系一致呢?
我:訂閱關(guān)系一致是指同一個消費者組下所有消費者所訂閱的 Topic、Tag 必須完全一致。如下圖所示:
其中,消費組 1 中的消費組都訂閱了 Topic1 中的 Tag1,消費組 2 中的消費組都訂閱了 Topic1 中的所有 Tag 以及 Topic2 中的 Tag1 || Tag2,消費組 3 中的消費組都訂閱了 Topic2 中的 Tag1 和 Tag2。
面試官:能舉幾個訂閱關(guān)系不一致的例子嗎?
我:訂閱不一致的情況有三種,如下圖:
消費組 1 的 Consumer1 和 Consumer2 都訂閱了 Topic1,但是訂閱的 Tag 不一致。
消費組 2 的 Consumer1 和 Consumer2 訂閱的 Topic 不一致。
消費組 3 的 Consumer1 和 Consumer2 訂閱的 Topic 和 Tag 都一致,但是訂閱 Tag 的順序不一致。
面試官:為什么訂閱關(guān)系不一致會導(dǎo)致消息丟失呢?
我:RocketMQ 的存儲架構(gòu),如下圖:
為了 提高消費效率,RocketMQ 引入了 ConsumeQueue,ConsumerQueue 中保存消息在 CommitLog 文件中的物理偏移量。ConsumerQueue 中的元素內(nèi)容如下:
- 前 8 個字節(jié)記錄消息在 CommitLog 中的偏移量。
- 中間 4 個字節(jié)記錄消息消息大小。
- 最后 8 個字節(jié)記錄消息中 tag 的 hashcode。
這個 tag 的作用是過濾消息,假如一個 Consumer 訂閱了 Topic1 中的 Tag1,那這個 Consumer 拉取消息時,首先從 Name Server 獲取訂閱關(guān)系,得到當(dāng)前 Consumer 訂閱的所有 tag 的 hashcode 集合 codeSet。每次從 ConsumerQueue 獲取一條記錄,就要判斷最后 8 個字節(jié) tag hashcode 是否在 codeSet 中,比如 Tag2 不在 codeSet 中,就會被過濾掉。如下圖:
消費組 1 消費 Topic1 中的消息時,Consumer1 通過 ConsumeQueue1 和 ConsumeQueue2 進行消費,Consumer2 通過 ConsumeQueue3 和 ConsumeQueue4 進行消費,如果 Consumer1 訂閱了 Tag1, Consumer2 訂閱了 Tag2,那 Consumer1 從 ConsumeQueue1 和 ConsumeQueue2 消費消息時,就會把 Tag2 中的消息過濾掉,這樣即使 Consumer2 訂閱了 Tag2,也不能消費到 ConsumeQueue1 和 ConsumeQueue2 里 Tag2 中的消息了。
面試官:有沒有方法可以快速知道消費組中有沒有訂閱關(guān)系不一致的問題?
我:可以在 RocketMQ 的控制臺看到。在 RocketMQ 的實例列表中,進入 Group 管理頁面,查看要查找的 Group ID,查看詳情,如下圖:(下圖來自阿里云)
面試官:恭喜你,通過了。