Rabbit Mq java客户端并行消费

时间:2013-10-08 13:24:45

标签: java rabbitmq apache-camel

我想并行处理来自rabbitMq队列的消息。队列配置为autoAck = false。我正在使用对camel endpoints的camel-rabbitMQ支持,它支持threadPoolSize参数,但这没有达到预期的效果。即使threadpoolsize = 20,消息仍然会从队列中串行处理。

从调试到代码,我可以看到threadpoolsize参数用于创建一个ExecutorService,用于传递给rabbit connectionfactory,如here所述。这一切看起来都很好,直到你进入兔子ConsumerWorkService。这里消息以最大16个消息的块处理。块中的每个消息都是串行处理的,如果还有更多工作要做,则执行器服务将在下一个块中调用。这个代码片段如下。从执行器服务的这种使用,我无法看到如何并行处理消息。执行者服务一次只能执行一项工作。

我想念的是什么?

private final class WorkPoolRunnable implements Runnable {

        public void run() {
            int size = MAX_RUNNABLE_BLOCK_SIZE;
            List<Runnable> block = new ArrayList<Runnable>(size);
            try {
                Channel key = ConsumerWorkService.this.workPool.nextWorkBlock(block, size);
                if (key == null) return; // nothing ready to run
                try {
                    for (Runnable runnable : block) {
                        runnable.run();
                    }
                } finally {
                    if (ConsumerWorkService.this.workPool.finishWorkBlock(key)) {
                        ConsumerWorkService.this.executor.execute(new WorkPoolRunnable());
                    }
                }
            } catch (RuntimeException e) {
                Thread.currentThread().interrupt();
            }
        }

2 个答案:

答案 0 :(得分:4)

RabbitMQ的文档对此并不十分清楚,但是,即使ConsumerWorkService使用了线程池,这个池似乎并没有以并行处理消息的方式使用:

  

每个频道都有自己的调度线程。对于每个渠道一个消费者的最常见用例,这意味着消费者不会阻止其他消费者。如果每个频道有多个消费者,请注意长时间运行的消费者可能会阻止向该频道上的其他消费者发送回调。

http://www.rabbitmq.com/api-guide.html

本文档建议每个线程使用一个Channel,事实上,如果您只需创建与所需并发级别一样多的Channel,就会在链接到这些通道的消费者之间分派消息

我已经测试了2个频道和消费者:当队列中有2条消息时,每个消费者一次只挑选一条消息。你提到的16条消息块似乎没有干扰,这是一件好事。

事实上,Spring AMQP还创建了几个同时处理消息的渠道。这可以通过以下方式完成:

我也测试了这个按预期工作。

答案 1 :(得分:4)

如果你有一个Channel个实例,那么它会通过检查ConsumerWorkService来正确地发现你注册的消费者。有两种方法可以解决这个问题:

  1. 使用多个渠道而不是一个。
  2. 使用单一渠道,但以特殊方式实施消费者。他们应该从队列中选择传入的消息并将其作为任务放入内部线程池中。
  3. 您可以在this post中找到更多详情。