RabbitMQ RPC跨多个rabbitMQ实例

时间:2015-02-14 22:00:52

标签: rabbitmq spring-amqp federation rabbitmq-shovel

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

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

enter image description here

使用铲子插件,我可以将所有booking.request消息从app1-3转发到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的同一个实例,也只是指定不同的vhost:

enter image description here

更新

根据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));

//并且消息发布到两个队列

我说错了吗?

2 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:2)

已经有一段时间了,但如果你使用Spring,你可以创建任意数量的连接工厂,使用自己的配置(主机,用户/通道,vhost等),就像你一样:

@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时Spring不知道选择哪一个,您必须提供name标记以启用一个主bean。

手中拿着它,只需沿着你的组件正常注射它们:

@Autowired
private RabbitTemplate template;

// ...

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

希望它有所帮助! :)