我目前正在评估如何管理多个Spring应用程序上下文(即Tomcat集群)之间的事件同步的一些想法。
在该用例中,每个上下文都可以生成事件X(无论是 Spring上下文事件还是自制事件),必须将其广播到所有其他上下文实例。这个事件只在它的“生命周期”中有效,这意味着我不想以任何方式坚持它(因为它们很多,并且它们的状态在几分钟之后就会过时)。
我的想法是使用已经存在的RabbitMQ实例。但是,标准的生产者/消费者模式将不适合,因为该事件应该向所有消费者广播。每个消费者都是生产者......就像聊天室一样。
问题1:RabbitMQ(+ Spring Integration)可以实现吗?如何构建这样的广播消息设置?
问题2:这是否可行?有没有人有更好的解决方案/想法?
用例:每个Web应用程序上下文都可以生成“user x invites user y”等事件,这些事件应该通过Websocket或EventSource或其他方式尽快传输到用户的浏览器。因为这是(已经)运行请求,所以动作地点(服务器1)可能不是消费地点(服务器2)。
解决方案的主要目标是:
在阅读了Gary Russell之后,我已经玩了一点点。
<beans profile="rabbit">
<rabbit:connection-factory id="connectionFactory" channel-cache-size="10" host="${rabbitmq.host}"
port="${rabbitmq.port}" username="${rabbitmq.username}"
password="${rabbitmq.password}" virtual-host="${rabbitmq.virtualhost}"/>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:queue id="eventQueue" name="${rabbitmq.queue.springevents}" auto-delete="false" durable="true"></rabbit:queue>
<bean id="amqpTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="exchange" value="${rabbitmq.springevents.exchange.fanout}"/>
<property name="replyTimeout" value="${rabbitmq.replyTimeout}"/>
</bean>
<!-- Receiving -->
<int-amqp:inbound-channel-adapter connection-factory="connectionFactory" channel="mqEventInChannelJson"
queue-names="${rabbitmq.queue.springevents}"/>
<!-- Sending -->
<int-amqp:outbound-channel-adapter channel="mqEventOutChannelJson" amqp-template="amqpTemplate" routing-key=""
exchange-name="${rabbitmq.springevents.exchange.fanout}" />
</beans>
频道mqEventOutChannelJson - &gt; Rabbit Exchange(amqp.fanout) - &gt;
如果我使用此配置,多个并行启动将跳过事件,因为所有正在运行的进程都在同一队列上运行( rabbitmq.queue.springevents )。是否有可能创建自定义队列名称而不为每个节点提供不同的配置?
我已经使用单独的Virtualhost和交换 amqp.fanout 测试了它。与特定扇出交换相同。
为了确保每个消费者拥有自己的队列,我为每个消费者创建了一个唯一的应用程序ID。
bean 应用程序本身创建了一个唯一标识符:
@Component("application")
public class Application {
private String id;
@PostConstruct
public void initialize() {
id = "app" + Math.round(1000 * Math.random());
}
public String getId() {
return id;
}
}
鉴于此,我可以动态创建一个在公共交换机上注册的唯一队列。无需外部配置步骤。
<util:property-path id="applicationId" path="application.id" />
<rabbit:queue id="eventQueue" name="${rabbitmq.queue.springevents}_#{applicationId}" auto-delete="true" durable="true" exclusive="true">
<rabbit:queue-arguments>
<!-- Attention if you want to declare mixed value types: https://jira.springsource.org/browse/AMQP-198 -->
<entry key="x-message-ttl">
<value type="java.lang.Long">${rabbitmq.queue.ttl}</value>
</entry>
</rabbit:queue-arguments>
</rabbit:queue>
答案 0 :(得分:1)
您可以使用RabbitMQ topic exchange或fanout exchange并让每个使用者绑定一个队列。完全由Spring AMQP和Spring Integration支持。