记一次故障排查:rocketmq消费状态NOT_CONSUME_YET

一、故障状态

消息发送成功,但是消费状态都为NOT_CONSUME_YET

img

image.png

二、trackType状态含义

通过查询RocketMQ-Dashboard的源码

 public enum TrackType {
    CONSUMED,               //  消息已经被消费
    CONSUMED_BUT_FILTERED,  //  消息已经投递但被过滤
    PULL,                   //  消息消费的方式是拉模式
    NOT_CONSUME_YET,        //  目前没有被消费
    NOT_ONLINE,            //   CONSUMER不在线
    UNKNOWN                //   未知错误
}

“已消费”是如何定义的?

broker中有个map用来保存每个queue的消费进度,如果queue的offset大于被查询消息的offset则消息被消费否则没有被消费。

三、查看消息分布情况

img

在当前group下,都集中在broker-a 下queue0中,最后的消费时间lastTimeStamp,正好是发生事故状态的时间点。

四、大胆假设

producer可能将消息都发送到broker-a 下queue0,而没有相应的consumer去消费此队列下的数据,导致现在故障发生。

五、确定消息的发送队列----- 隐藏技能

通过查看RocketMQ-Dashboard的源码,发现Dashboard其实返回了消息的很多信息,但是并没有在页面展示出来,直接看接口返回。如此我们确定了消息的发送队列

img

六、解决

生产者负载均衡的策略,与消费者的负载均衡策略不同,导致未能正常消费
解决方案: 修改消费的这消费queue,问题解决。

RocketMQPushConsumerLifecycleListener 文件
  @Override
    public void prepareStart(DefaultMQPushConsumer consumer) {
        // set consumer consume message from now
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);
        consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));
        AllocateMessageQueueStrategyUtil.setUpAllocateStrategy(consumer);
    }


// 文件 AllocateMessageQueueStrategyUtil
public final class AllocateMessageQueueStrategyUtil {

    /** 构造方法 */
    private AllocateMessageQueueStrategyUtil() {
    }

    //"CHECKSTYLE:OFF"
    /** 分配策略 */
    static AllocateMessageQueueStrategy allocateMessageQueueStrategy = new AllocateMessageQueueStrategy() {
        @Override
        public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> queueList,
                                           List<String> cidAll) {

            String allocateStrategy = SpringActiveProfileUtil.getBean("nacosProperties", NacosProperties.class)
                    .getMqAllocateStrategy();
            List<MessageQueue> list = new ArrayList<>();
            Integer strategyInteger = Integer.valueOf(allocateStrategy);
            list.add(queueList.get(strategyInteger));
            return list;
        }

        @Override
        public String getName() {
            return "divide_by_queue";
        }
    };

    /**
     * 设置分配策略
     * @param consumer consumer
     */
    public static void setUpAllocateStrategy(DefaultMQPushConsumer consumer) {

        if (SpringActiveProfileUtil.getActiveProfile().equals("test")
                || SpringActiveProfileUtil.getActiveProfile().equals("dev")) {
            consumer.setAllocateMessageQueueStrategy(AllocateMessageQueueStrategyUtil.allocateMessageQueueStrategy);
        }
    }
}
posted @ 2023-01-05 17:08  崔安兵  阅读(1681)  评论(0编辑  收藏  举报