【问题标题】:RabbitMQ RPC across multiple rabbitMQ instances跨多个 rabbitMQ 实例的 RabbitMQ RPC
【发布时间】:2015-04-15 17:53:26
【问题描述】:

我有三个客户端,每个客户端都有自己的 RabbitMQ 实例,我有一个应用程序(我们称之为 appA),它有自己的 RabbitMQ 实例,三个客户端应用程序(app1、app2、app3)想要使用应用A。

appA上的服务需要RPC通信,app1、app2、app3各有一个booking.request队列和一个booking.response队列。

使用 shovel 插件,我可以将 app1-3 中的所有 booking.request 消息转发到 appA:

Shovel1 
virtualHost=appA, 
name=booking-request-shovel, 
sourceURI=amqp://userForApp1:password@app1-server/vhostForApp1
queue=booking.request
destinationURI=amqp://userForAppA:password@appA-server/vhostForAppA
queue=booking.request

setup another shovel to get booking requests from app2 and app3 to appA in the same way as above.

现在 appA 将响应 booking.response 队列上的请求,我需要 rabbitMQ-appA 上的预订响应消息返回到 app1、app2 或 app3 上的正确 booking.response 队列,但不是全部他们 - 我如何在rabbitMQ-appA上设置一个铲子/联合队列,将响应转发回正确的rabbitMQ(app1,app2,app3),期望在他们自己的booking.response队列中得到响应?

所有这些应用程序都在使用 spring-amqp(如果相关) 或者,我可以在 Spring 中设置一个 rabbitMQ 模板,它监听多个 rabbitMQ 队列并从每个队列中消费。

从文档中可以看出,典型的消费者是这样的:

<rabbit:listener-container connection-factory="rabbitConnectionFactory">
    <rabbit:listener queues="some.queue" ref="somePojo" method="handle"/>
</rabbit:listener-container>

是否可以指定多个连接工厂来执行此操作,即使连接工厂指向同一个 RabbitMQ 实例,但只是不同的虚拟主机:

更新

根据 Josh 的回答,我会有多个连接工厂:

 <rabbit:connection-factory
                id="connectionFactory1"
                port="${rabbit.port1}"
                virtual-host="${rabbit.virtual1}"
                host="${rabbit.host1}"
                username="${rabbit.username1}"
                password="${rabbit.password1}"
                connection-factory="nativeConnectionFactory" />

 <rabbit:connection-factory
                id="connectionFactory2"
                port="${rabbit.port2}"
                virtual-host="${rabbit.virtual2}"
                host="${rabbit.host2}"
                username="${rabbit.username2}"
                password="${rabbit.password2}"
                connection-factory="nativeConnectionFactory" />

然后我会使用 SimpleRoutingConnectionFactory 来包装两个连接工厂:

<bean id="connectionFactory" class="org.springframework.amqp.rabbit.connection.SimpleRoutingConnectionFactory">
    <property name="targetConnectionFactories">
        <map>
            <entry key="#{connectionFactory1.virtualHost}" ref="connectionFactory1"/>
            <entry key="#{connectionFactory2.virtualHost}" ref="connectionFactory2"/>
        </map>
    </property>
</bean>

现在,当我声明我的 rabbitMQ 模板时,我会将它指向 SimpleRoutingConnectionFactory 而不是单个连接工厂:

<rabbit:template id="template" connection-factory="connectionFactory" />

...然后像我通常使用的那样使用模板...

<rabbit:listener-container
        connection-factory="connectionFactory"
        channel-transacted="true"
        requeue-rejected="true"
        concurrency="${rabbit.consumers}">
        <rabbit:listener queues="${queue.booking}" ref="TransactionMessageListener" method="handle"  />
</rabbit:listener-container>

// 两个rabbitMQ实例都使用消息

...和...

  @Autowired
  private AmqpTemplate template;

  template.send(getExchange(), getQueue(), new Message(gson.toJson(message).getBytes(), properties));

// 消息发布到两个队列

我说的对吗?

【问题讨论】:

标签: rabbitmq spring-amqp federation rabbitmq-shovel


【解决方案1】:

看看 org.springframework.amqp.rabbit.connection.AbstractRoutingConnectionFactory。它将允许您为不同的 vhost 或不同的 rabbitmq 实例创建多个连接工厂。我们将它用于多租户 rabbitmq 应用程序。

【讨论】:

  • AbstractRoutingConnectionFactory 看起来很有希望,你有如何使用它的例子吗?确定CurrentLookupKey 的用途是什么?
  • 这是上面的 spring 文档。 http://docs.spring.io/spring-amqp/docs/1.3.0.M1/reference/html/amqp.html#routing-connection-factory。如果您在阅读该文档后有任何问题,请告诉我。
  • 基于文档,我更新了我的问题……简而言之,SimpleRoutingConnectionFactory 包装了多个连接工厂,然后可以像单个连接工厂一样使用,对吗?
  • 如果我可以拥有多个侦听器容器和多个 amqp 模板(我假设 spring 允许这样做?)并直接或通过将它们组合在一起的 SimpleRoutingConnectionFactory 使用它们,那么这解决了我的问题将允许我在一个 vHost 上进行操作,并同时选择性地在其他 vHost 上的其他队列/交换上操作(只能在下周进行测试,目前在一个 dart 项目中深入研究,因此所有问题)
  • 是的,您可以拥有多个 SimpleMessageListenerContainer 实例和多个 AmqpTemplate 实例。但是每个都配置了一个 ConnectionFactory。如果您在开发时已知固定数量的虚拟主机,您应该能够编写简单的逻辑来确定在发送消息时使用哪个 AmqpTemplate。然后为您需要的每个虚拟主机单独设置 SimpleMessageListenerContainers。如果您希望一个 AmqpTemplate 跨多个虚拟主机工作,那么您需要 AbstractRoutingConnectionFactory。
【解决方案2】:

已经有一段时间了,但是如果您使用 Spring,您可以使用自己的配置(主机、用户/密码、虚拟主机等)创建任意数量的连接工厂,就像您所做的那样:

@Bean
@Primary
public ConnectionFactory amqpConnectionFactory1() {
    final CachingConnectionFactory connectionFactory = new CachingConnectionFactory();

    connectionFactory.setAddresses("...");
    connectionFactory.setUsername("...");
    connectionFactory.setPassword("...");
    connectionFactory.setVirtualHost("...");

    return connectionFactory;
}

@Bean
public ConnectionFactory amqpConnectionFactory2() {
    final CachingConnectionFactory connectionFactory = new CachingConnectionFactory();

    // ...

    return connectionFactory;
}

还有你的兔子管理员/模板:

@Bean
@Primary
public RabbitAdmin rabbitAdmin1() {
    return new RabbitAdmin(amqpConnectionFactory1());
}

@Bean
public RabbitAdmin rabbitAdmin2() {
    return new RabbitAdmin(amqpConnectionFactory2());
}

// ...

@Bean
@Primary
public RabbitTemplate rabbitTemplate1() {
    RabbitTemplate rabbitTemplate = new RabbitTemplate(amqpConnectionFactory1());

    // ...

    return rabbitTemplate;
}

@Bean
public RabbitTemplate rabbitTemplate2() {
    RabbitTemplate rabbitTemplate = new RabbitTemplate(amqpConnectionFactory2());

    // ...

    return rabbitTemplate;
}

请注意,您必须提供@Primary 标签才能启用一个主bean,一旦Spring 不知道选择哪一个,而您没有明确通知name

有了这个,只需在你的组件中正常注入它们:

@Autowired
private RabbitTemplate template;

// ...

@Autowired
@Qualifier("rabbitTemplate2") // Needed when want to use the non-primary bean
private RabbitTemplate template;

希望对您有所帮助! :)

【讨论】:

  • 不同模板如何实现org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback
猜你喜欢
  • 2020-11-24
  • 1970-01-01
  • 1970-01-01
  • 2018-08-04
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多