记一次故障排查:rocketmq消费状态NOT_CONSUME_YET
一、故障状态
消息发送成功,但是消费状态都为NOT_CONSUME_YET
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则消息被消费否则没有被消费。
三、查看消息分布情况
在当前group下,都集中在broker-a 下queue0中,最后的消费时间lastTimeStamp,正好是发生事故状态的时间点。
四、大胆假设
producer可能将消息都发送到broker-a 下queue0,而没有相应的consumer去消费此队列下的数据,导致现在故障发生。
五、确定消息的发送队列----- 隐藏技能
通过查看RocketMQ-Dashboard的源码,发现Dashboard其实返回了消息的很多信息,但是并没有在页面展示出来,直接看接口返回。如此我们确定了消息的发送队列
六、解决
生产者负载均衡的策略,与消费者的负载均衡策略不同,导致未能正常消费
解决方案: 修改消费的这消费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);
}
}
}