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