跨多个 rabbitMQ 实例的 RabbitMQ RPC
RabbitMQ RPC across multiple rabbitMQ instances
我有三个客户端,每个客户端都有自己的 RabbitMQ 实例,我有一个应用程序(我们称之为 appA),它有自己的 RabbitMQ 实例,三个客户端应用程序(app1、app2、app3)想要使用一个appA 上的服务。
appA上的服务需要RPC通信,app1、app2、app3各有一个booking.request队列和一个booking.response队列。
使用 shovel 插件,我可以将所有 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 实例,但只是不同的虚拟主机:
更新:
根据 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));
// 消息发布到两个队列
我说得对吗?
看看org.springframework.amqp.rabbit.connection.AbstractRoutingConnectionFactory。它将允许您为不同的虚拟主机或不同的 rabbitmq 实例创建多个连接工厂。我们将它用于多租户 rabbitmq 应用程序。
已经有一段时间了,但是如果您正在使用 Spring,您可以根据需要创建任意数量的连接工厂,并使用它们自己的配置(主机、user/pass、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;
}
你的兔子 admin/template 就这样:
@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;
希望对您有所帮助! :)
我有三个客户端,每个客户端都有自己的 RabbitMQ 实例,我有一个应用程序(我们称之为 appA),它有自己的 RabbitMQ 实例,三个客户端应用程序(app1、app2、app3)想要使用一个appA 上的服务。
appA上的服务需要RPC通信,app1、app2、app3各有一个booking.request队列和一个booking.response队列。
使用 shovel 插件,我可以将所有 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 实例,但只是不同的虚拟主机:
更新:
根据 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));
// 消息发布到两个队列
我说得对吗?
看看org.springframework.amqp.rabbit.connection.AbstractRoutingConnectionFactory。它将允许您为不同的虚拟主机或不同的 rabbitmq 实例创建多个连接工厂。我们将它用于多租户 rabbitmq 应用程序。
已经有一段时间了,但是如果您正在使用 Spring,您可以根据需要创建任意数量的连接工厂,并使用它们自己的配置(主机、user/pass、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;
}
你的兔子 admin/template 就这样:
@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;
希望对您有所帮助! :)