一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情
RocketMQ 消费者订阅topic问题
集群消费
广播消费
消息消费订阅消息
消费者组需要订阅多个 Topic 时,可以重复调用 subscribe方法,指定不同的 topic。
下面的代码中, 一个消费者组 same_group, 需要订阅 Topic1 和 Topic2
消费者订阅消息一致
一般来说一个进程只写一个消费组代码,如何写的两个消费者代码,订阅 topic 信息完全一致时,
消息者1
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer( "same_group");
consumer.setNamesrvAddr("10.227.12.225:9876");
consumer.subscribe("Topic1", "*");
consumer.subscribe("Topic2", "*");
consumer.setInstanceName("instance1")
consumer.registerMessageListener(...); //注册监听器,略
consumer.start();
消费者2
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer( "same_group");
consumer.setNamesrvAddr("10.227.12.225:9876");
consumer.subscribe("Topic1", "*");
consumer.subscribe("Topic2", "*");
consumer.setInstanceName("instance2")
consumer.registerMessageListener(...); //注册监听器,略
consumer.start();
区别在于setInstanceName,但是两个消费者订阅信息完全一致,会正常进行 rebalance 会提示消费者订阅消息相同:
Same subscription in the same group of consumer
Rebalance OK
订阅topic不一致
假设一个进程启动两个消费者,一个订阅一个 topic1 ,一个订阅一个 topic2
消费者1
只订阅 topic1
DefaultMQPushConsumer consumer1 = new DefaultMQPushConsumer( "no_same_group");
consumer1.setNamesrvAddr("10.227.12.225:9876");
consumer1.setInstanceName("instance1");
consumer1.subscribe("Topic1", "*");
...
消费者2
只订阅 Topic2
DefaultMQPushConsumer consumer2 = new DefaultMQPushConsumer( "no_same_group");
consumer2.setNamesrvAddr("10.227.12.225:9876");
consumer2.setInstanceName("instance2");
consumer2.subscribe("Topic2", "*");
...
消费者1 和消费者2属于同一个消费者组 no_same_group,但是一个 topic1,另外一个订阅 topic2
会提示订阅信息不一致的警告,订阅信息不一致,会导致分区无法正常分配
WARN: Different subscription in the same group of consumer!!!
生产者发送已经分配给消费者的队列的消息依然可以继续消费,但是发送到未分配到队列则无法进行消费,也就是说,生产者发送的消息,部分可以消费,部分无法消费。
为啥会报错
看源码中 org.apache.rocketmq.broker.processor.PullMessageProcessor#processRequest: 将 topic 订阅信息找出来,如果没有找到,所以报消费订阅不存在的错误。
subscriptionData = consumerGroupInfo.findSubscriptionData(requestHeader.getTopic());
if (null == subscriptionData) {
log.warn("the consumer's subscription not exist, group: {}, topic:{}", requestHeader.getConsumerGroup(), requestHeader.getTopic());
response.setCode(ResponseCode.SUBSCRIPTION_NOT_EXIST);
response.setRemark("the consumer's subscription not exist" + FAQUrl.suggestTodo(FAQUrl.SAME_GROUP_DIFFERENT_TOPIC));
return response;
}
那么为啥 topic 信息会找不到呢?
消费者的订阅信息在 broker 中时以 group 来分组的,具体查看 org.apache.rocketmq.broker.client.ConsumerManager:
private final ConcurrentMap<String/* Group */, ConsumerGroupInfo> consumerTable =
new ConcurrentHashMap<String, ConsumerGroupInfo>(1024);
也就是说,集群中每个消费者在向 broker 注册订阅信息的时候会相互覆盖对方的订阅信息。 这样就是为啥同一个消费者订阅关系都不一样,出现了订阅信息覆盖的问题。