私は現在、複数の Spring アプリケーション コンテキスト、つまり Tomcat クラスター間のイベント同期を管理する方法についていくつかのアイデアを評価しています。
そのユースケースでは、各コンテキストは、他のすべてのコンテキストインスタンスにブロードキャストする必要があるイベント X ( Spring コンテキストイベントまたは自作イベントに関係なく) を生成できます。イベントはその「ライフサイクル」でのみ有効です。つまり、それを永続化したくないということです(イベントは多く、数分後に状態が廃止されるため)。
私の考えは、既に存在する RabbitMQ インスタンスを使用することです。ただし、イベントはすべてのコンシューマーにブロードキャストする必要があるため、標準のプロデューサー/コンシューマー パターンは適合しません。各コンシューマは、チャットルームのようなプロデューサーです。
Q #1: これは RabbitMQ (+Spring Integration) で可能ですか? このようなブロードキャスト メッセージのセットアップを構築するにはどうすればよいですか?
Q #2: これは可能かどうか? 誰かがより良い解決策/アイデアを持っていますか?
ユースケース: 各 Web アプリケーションコンテキストは、「ユーザー x がユーザー y を招待する」などのイベントを生成できます。これは、Websocket または EventSource などを介してユーザーのブラウザーにできるだけ早く転送する必要があります。これは (すでに) 実行中の要求であるため、アクションの場所 (サーバー 1) が消費の場所 (サーバー 2) ではない可能性があります。
ソリューションの主な目標は次のとおりです。
- (比較的) 高速でスケーラブル。
- ファイア&フォーゲット。メッセージが送信された場合は、破棄します。メッセージが無関係である場合は、忘れてください。持続しません。RabbitMQ では、これを TTL で行うことができました。
- メッセージはモデルに対してシリアライズされています。つまり、Jackson などを使用しています。
- (アクティブな) コンテキスト/ノードの数に基づく手動構成はありません。追加のコンテキスト (Web サーバー、バックエンド プロセスなど) を追加する場合、同期のセットアップを変更したくありません。
更新 1
Gary Russellの anwser を読んだ後、少しプレイしてみました。
<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 -> Rabbit Exchange (amqp.fanout) ->
この構成を使用すると、実行中のすべてのプロセスが同じキュー ( rabbitmq.queue.springevents ) で実行されるため、複数の並列開始でイベントがスキップされます。各ノードに異なる構成を提供せずにカスタム キュー名を作成する可能性はありますか?
別の Virtualhost と交換amqp.fanoutでテストしました。特定の Fanout 交換と同じ。
更新 2
各コンシューマが独自のキューを持つようにするために、それぞれに一意のアプリケーション 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>