自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

RocketMQ消息丟失如何排查?

開發(fā) 前端
我們在RocketMQ-Dashboard上其實就能看到每個隊列broker端的offset(代理者位點)以及消息消費的offset(消費者位點),差值就是沒有被消費的消息。

消息丟失如何排查?當我們在使用mq的時候,經常會遇到消息消費異常的問題,原因有很多種,比如:

  • producer發(fā)送失敗
  • consumer消費異常
  • consumer根本就沒收到消息

「那么我們該如何排查了?」

其實借助RocketMQ-Dashboard就能高效的排查,里面有很多你想象不到的功能。

首先我們先查找期望消費的消息,查找的方式有很多種,根據消息id,時間等。

「消息沒找到?」

說明proder發(fā)送異常,也有可能是消息過期了,因為rocketmq的消息默認保存72h,此時到producer端的日志進一步確認即可。

「消息找到了!」

接著看消息的消費狀態(tài),如下圖消息的消費狀態(tài)為NOT_ONLINE。

「NOT_ONLINE代表什么含義呢?」

別著急,我們一步步來分析,先看看TrackType到底有多少種狀態(tài)。

public enum TrackType {
CONSUMED,
CONSUMED_BUT_FILTERED,
PULL,
NOT_CONSUME_YET,
NOT_ONLINE,
UNKNOWN
}

每種類型的解釋如下:

類型

解釋

CONSUMED

消息已經被消費

CONSUMED_BUT_FILTERED

消息已經投遞但被過濾

PULL

消息消費的方式是拉模式

NOT_CONSUME_YET

目前沒有被消費

NOT_ONLINE

CONSUMER不在線

UNKNOWN

未知錯誤

「怎么判定消息已經被消費?」

上一節(jié)我們講到,broker會用一個map來保存每個queue的消費進度,「如果queue的offset大于被查詢消息的offset則消息被消費,否則沒有被消費」(NOT_CONSUME_YET)。

我們在RocketMQ-Dashboard上其實就能看到每個隊列broker端的offset(代理者位點)以及消息消費的offset(消費者位點),差值就是沒有被消費的消息。

當消息都被消費時,差值為0,如下圖所示:

「CONSUMED_BUT_FILTERED表示消息已經投遞,但是已經被過濾掉了」。例如producer發(fā)的是topicA,tagA,但是consumer訂閱的卻是topicA,tagB。

「CONSUMED_BUT_FILTERED(消息已經被投遞但被過濾)是怎么發(fā)生的呢?」

這個就不得不提到RocketMQ中的一個概念,「消息消費要滿足訂閱關系一致性,即一個consumerGroup中的所有消費者訂閱的topic和tag必須保持一致,不然就會造成消息丟失」。

如下圖場景,發(fā)送了4條消息,consumer1訂閱了topica-taga,而consumer2訂閱了topica-tab。consumer1消費q0中的數據,consumer2消費q1中的數據。

投遞到q0的msg-1和msg-3只有msg-1能被正常消費,而msg-3則是CONSUMED_BUT_FILTERED。因為msg-3被投遞到q0,但是consumer1不消費tagb的消息導致消息被過濾,造成消息丟失。

同理msg-2這條消息也會丟失。

「注意,還有一個非常重要的點」!

雖然消息消費失敗了,但是消息的offset還會正常提交,即 「消息消費失敗了,但是狀態(tài)也會是CONSUMED」。

「RocketMQ認為消息消費失敗需要重試的場景有哪些?」

  • 返回ConsumeConcurrentlyStatus.RECONSUME_LATER
  • 返回null
  • 主動或被動拋出異常

「那么消費失敗的消息去哪了呢?」

當消息消費失敗,會被放到重試隊列中,Topic名字為%RETRY% + consumerGroup。

「Consumer沒訂閱這個topic啊,怎么才能消費到重試消息?」

其實在Consumer啟動的時候,框架內部幫你訂閱了這個topic,所以重試消息能被消費到。

「另外消息不是一直重試,而是每隔1段時間進行重試」

第幾次重試

與上次重試的間隔時間

第幾次重試

與上次重試的間隔時間

1

10 秒

9

7 分鐘

2

30 秒

10

8 分鐘

3

1 分鐘

11

9 分鐘

4

2 分鐘

12

10 分鐘

5

3 分鐘

13

20 分鐘

6

4 分鐘

14

30 分鐘

7

5 分鐘

15

1 小時

8

6 分鐘

16

2 小時

當消息超過最大消費次數16次,會將消息投遞到死信隊列中,死信隊列的topic名為%DLQ% + consumerGroup。

「因此當你發(fā)現消息狀態(tài)為CONSUMED,但是消費失敗時,去重試隊列和死信隊列中找就行了」。

消息消費異常排查實戰(zhàn)

這個問題發(fā)生的背景是這樣的,就是我們有2個系統(tǒng),中間通過mq來保證數據的一致性,結果有一天數據不一致了,那肯定是consumer消費消息有問題,或者producer發(fā)送消息有問題。

先根據時間段找到了消息,確保了發(fā)送沒有問題,接著看消息的狀態(tài)為NOT_CONSUME_YET,說明consumer在線但是沒有消息。

「NOT_CONSUME_YET表明消息沒有被消費」,但是消息發(fā)送都過了好長時間了,consumer不應該沒消費啊,查日志consumer確實沒有消費。

用RocketMQ-Dashboard查看一下代理者位點和消費者位點,0隊列正常消費,其他隊列沒有被消費。

「感覺這個負載均衡策略有點問題啊,怎么0隊列這么多消息,別的隊列都怎么沒消息,問一波中間件的同學,是不是又改負載均衡策略了?」

確實改了!測試環(huán)境下,采用隊列緯度區(qū)分多環(huán)境,0是基準環(huán)境,我們團隊目前還沒有用多環(huán)境,所以收發(fā)消息都會在隊列0上,其他隊列不會用到(「你可以簡單認為測試環(huán)境發(fā)送和消費消息只會用到0隊列」)。

「那么問題來了!」

首先消息的狀態(tài)是NOT_CONSUME_YET,說明消息肯定被投遞到0隊列之外了,但是中間件的小伙伴卻說消息不會被投遞到0隊列。

要想驗證我的想法首先需要證明沒有被消費的消息確實被投遞到0隊列之外的隊列了。

中間走的彎路就不說了,直到我看了看RocketMQ-Dashboard的源碼,「發(fā)現Dashboard其實返回了消息的很多信息,但是并沒有在頁面展示出來,直接看接口返回」。

乖乖,發(fā)現了新世界,消息的所有屬性都在這了,看到queuId為14,果然驗證了我的想法。

再看bornHost居然是我們辦公室的網段。

「難道本地啟動的負載均衡策略和測試環(huán)境的負載均衡策略不一樣?」

本地debug一波代碼,果然是本地的producer會往所有的隊列發(fā)送消息,并且consumer也會消費所有隊列的消息。

「至此找出問題了!」

producer在本地啟了一個服務,注冊到測試環(huán)境的zk,測試環(huán)境的部分請求打到本地,往0隊列之外的隊列發(fā)了消息,但是測試環(huán)境的consumer只會消費0隊列中的消息,導致消息遲遲沒有被消費。

責任編輯:武曉燕 來源: Java識堂
相關推薦

2024-08-06 09:55:25

2023-12-21 08:01:41

RocketMQ消息堆積

2023-09-13 08:14:57

RocketMQ次數機制

2023-04-25 18:54:13

數據數據丟失

2021-08-04 07:47:18

Kafka消息框架

2024-10-29 08:34:27

RocketMQ消息類型事務消息

2024-11-11 13:28:11

RocketMQ消息類型FIFO

2024-02-04 09:02:29

RocketMQ項目處理器

2021-03-08 10:19:59

MQ消息磁盤

2021-02-02 11:01:31

RocketMQ消息分布式

2023-12-15 13:08:00

RocketMQ中間件消費順序

2022-12-22 10:03:18

消息集成

2021-04-27 07:52:18

RocketMQ消息投遞

2023-07-17 08:34:03

RocketMQ消息初體驗

2022-06-02 08:21:07

RocketMQ消息中間件

2025-04-09 08:20:00

RocketMQ消息隊列開發(fā)

2023-07-18 09:03:01

RocketMQ場景消息

2021-10-22 08:37:13

消息不丟失rocketmq消息隊列

2021-09-13 07:23:53

KafkaGo語言

2024-09-25 08:32:05

點贊
收藏

51CTO技術棧公眾號