RocketMQ Java消费端默认并发消费详解

34 阅读2分钟
  1. 默认并发消费的含义在RocketMQ的Java客户端中,消费者默认采用并发消费模式(即MessageListenerConcurrently)。这意味着消费者会启动多个线程并发的从Broker拉取消息并进行消费。

关键点:

  • 消费者会启动一个线程池(在DefaultMQPushConsumer内部管理)来处理拉取到的消息。- 拉取消息是由单独的线程(PullMessageService)完成的,然后提交到消费者线程池中并发执行。
  1. 并发获取消息和消费- 拉取消息:消费者启动后,会有一个长轮询的拉取服务(PullMessageService)不断地从Broker拉取消息。拉取到的消息会被放入一个处理队列(ProcessQueue)中,然后提交到消费者线程池。
  2. 消费消息:消费者线程池中的线程会并发地处理这些消息。每个消息都会交给用户实现的MessageListenerConcurrentlyconsumeMessage方法来处理

4.源码层面(以PushConsumer为例):

  • DefaultMQPushConsumerImplstart()方法中,会启动PullMessageServiceRebalanceService等。- 当拉取到消息后,PullCallbackonSuccess方法会被调用,然后通过ConsumeMessageConcurrentlyServicesubmitConsumeRequest方法提交消费请求。- 在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);
        }
    }
}