- 默认并发消费的含义在RocketMQ的Java客户端中,消费者默认采用并发消费模式(即
MessageListenerConcurrently)。这意味着消费者会启动多个线程并发的从Broker拉取消息并进行消费。
关键点:
- 消费者会启动一个线程池(在
DefaultMQPushConsumer内部管理)来处理拉取到的消息。- 拉取消息是由单独的线程(PullMessageService)完成的,然后提交到消费者线程池中并发执行。
- 并发获取消息和消费- 拉取消息:消费者启动后,会有一个长轮询的拉取服务(PullMessageService)不断地从Broker拉取消息。拉取到的消息会被放入一个处理队列(ProcessQueue)中,然后提交到消费者线程池。
- 消费消息:消费者线程池中的线程会并发地处理这些消息。每个消息都会交给用户实现的
MessageListenerConcurrently的consumeMessage方法来处理
4.源码层面(以PushConsumer为例):
- 在
DefaultMQPushConsumerImpl的start()方法中,会启动PullMessageService和RebalanceService等。- 当拉取到消息后,PullCallback的onSuccess方法会被调用,然后通过ConsumeMessageConcurrentlyService的submitConsumeRequest方法提交消费请求。- 在ConsumeMessageConcurrentlyService中,提交的消费请求(ConsumeRequest)会被放入线程池(consumeExecutor)中执行。
通过关键源码分析工作流程:
// 1. 消费者启动时初始化线程池
public class DefaultMQPushConsumerImpl {
private final ConcurrentMap<MessageQueue, ProcessQueue> processQueueTable = new ConcurrentHashMap<>();
private final ConsumeMessageService consumeMessageService;
public synchronized void start() {
// 创建并发消费服务(关键!)
this.consumeMessageService = new ConsumeMessageConcurrentlyService(...);
}
}
// 2. 消息拉取后的处理(PullCallback)
public class DefaultMQPushConsumerImpl {
private void pullMessage(PullRequest pullRequest) {
pullAPIWrapper.pullKernelImpl(..., new PullCallback() {
public void onSuccess(PullResult pullResult) {
// 提交消息到消费服务
ConsumeMessageConcurrentlyService.this.submitConsumeRequest(
pullResult.getMsgFoundList(),
processQueue,
messageQueue
);
}
});
}
}
// 3. 提交并发消费请求(核心逻辑)
public class ConsumeMessageConcurrentlyService {
private final ThreadPoolExecutor consumeExecutor; // 消费线程池
public void submitConsumeRequest(List<MessageExt> msgs, ...) {
// 将消息分批次提交到线程池(关键并发点!)
consumeExecutor.submit(new ConsumeRequest(msgs, processQueue, messageQueue));
}
class ConsumeRequest implements Runnable {
public void run() {
// 用户实现的监听器
MessageListenerConcurrently listener = DefaultMQPushConsumerImpl.this.messageListener;
ConsumeConcurrentlyStatus status = listener.consumeMessage(msgs, context);
// 处理消费结果(包含重试逻辑)
processConsumeResult(status, context, this);
}
}
}