【问题标题】:RabbitMQ, docker, single queue, multiple consumersRabbitMQ、docker、单队列、多消费者
【发布时间】:2018-05-06 02:43:56
【问题描述】:

我们在我们的系统中使用 Docker、Spring 和 RabbitMq。我是 AMQP 的新手,我正试图弄清楚我们系统中的交换、队列、绑定和连接是如何工作的。 我们有多个 dockerized 应用程序。

简而言之,当应用程序启动时,它们每个都开始监听同一个队列,我不明白它们是如何期望收到相同的消息的。 * 中有一些类似的问题,让我觉得我们当前的系统可能存在缺陷。

更详细的:

docker容器启动时,不同容器中的多个应用使用RabbitAdmin来

declare the same exchange: rabbitAdmin.declareExchange(exchange)
declare the same queue: rabbitAdmin.declareQueue(queue)
bind those together: rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(exhange).with("theSameKey");

他们这样做是因为他们想收听相同的消息。 据我了解,只有一个 dockerized 程序设法创建了交换和队列,其余程序尝试但没有任何效果。

之后,这些应用程序中的每一个都为队列创建并启动 SimpleMessageContainers:

simpleMessageContainer.setMessageListener(messageListener)
simpleMessageContainer.addQueueNames(queue.getName())
simpleMessageContainer.start()

使用rabbitmqctl和rabbitmq的web界面,可以看到单个队列在不同的channel上有多个consumer,对应不同的docker容器。

难道不是messageListener驻留在应用程序中,而是RabbitMq在调用addQueueNames时在broker处为队列创建一个Consumer,然后这个Consumer通过连接转发消息到应用程序本地messageListener?

由于不同 docker 容器中的多个应用程序都这样做,所以同一个队列有多个消费者,就像我在 rabbitmqctl 中看到的那样。

我不明白的是,RabbitMq 不会以循环方式将最终进入队列的消息传递给通道/消费者,以便只有一个 dockerized 应用程序会接收它? 交换是直接和主题​​类型的,没有扇出交换。 如果所有 dockerized 应用程序都想接收相同的消息,那么它们不应该都为相同的扩展创建一个自己的队列,具有自己的队列名称但具有相同的路由键吗?

我看不出当前的实现如何正常工作。

【问题讨论】:

    标签: java spring docker rabbitmq


    【解决方案1】:
    • 每个容器(实际上是内部运行的应用程序)都尝试声明交换和队列。一旦声明,所有其他声明命令都无效(即使参数不同)。

    RabbitMq 不会以循环方式将最终进入队列的消息传递给通道/消费者。

    没错。尽管您可以使用prefetch_count 和消息ack 来影响它。

    如果所有 dockerized 应用程序都想接收相同的消息,那么它们不应该都为同一个交换创建一个自己的队列,具有自己的队列名称但具有相同的路由键吗?

    是的,这是唯一的方法,因为根据 AMQP 协议,消息在消费者之间是负载平衡的。因此,如果所有容器(消费者)要处理相同的消息,它们每个都应该有不同的队列连接到同一个交换器(direct 路由就可以了)。

    无论消费者是使用 docker 还是其他方式运行都是如此。

    【讨论】:

      【解决方案2】:

      简而言之,当应用程序启动时,它们每个都开始收听同一个队列,我不明白它们如何期望收到相同的消息

      他们永远不会收到相同的消息。只有一个人会选择一条消息。

      要执行您的要求 - 都收到相同的消息 - 它必须是 Topic,而不是 Queue

      顺便说一句:Docker 或容器没有什么特别之处,多个消费者可以以多种方式运行。作为经典集群环境中的示例。

      【讨论】: