競合するコンシューマー パターンとリース パターンの組み合わせを使用して、1 日あたり 150 万以上のメッセージというかなり大規模なクラスター内のメッセージの順次処理を実行しました。
ただし、ここにキッカーがあります-一度に1つのトランザクションしか処理できないという要件は、目標を達成するのを妨げます. 基本的な要件は同じで、メッセージは順番に処理する必要がありました。少なくとも、私たちはそう思っていました。その後、ひらめきがありました。問題をさらに考えてみると、完全な順序付けは必要ないことに気付きました。実際には、各アカウント内でのみ注文する必要がありました。したがって、クラスター内のさまざまなサーバーにアカウントの範囲を割り当てることで、クラスター内のサーバー間で負荷を分散できます。次に、各サーバーは、特定のアカウントのメッセージを順番に処理する責任がありました。
これが 2 番目の巧妙な部分です。クラスタ内のさまざまなサーバーにアカウント範囲を動的に割り当てるリース パターンを使用しました。クラスター内の 1 つのサーバーがダウンした場合、別のサーバーがリースを取得し、最初のサーバーの責任を引き継ぎます。
これは私たちにとってはうまくいき、プロセスは会社の合併のために置き換えられるまで約 4 年間実稼働していました。
編集:
このソリューションについては、こちらで詳しく説明しています: http://coders-log.blogspot.com/2008/12/favorite-projects-series-installment-2.html
編集:
わかりました。すでに必要なレベルで処理を行っていますが、クラスターにデプロイされているため、MDB の 1 つのインスタンスのみがキューからアクティブにメッセージをプルしていることを確認する必要があります。さらに、最も単純で実行可能なソリューションが必要です。
現在持っている MDB メカニズムを放棄する必要はないと思います。基本的にここで話しているのは、分散ロック メカニズムの要件であり、派手な言い回しではありません。
だから、これを提案させてください。MDB がキューからメッセージを受信するように登録する時点で、分散ロックをチェックし、それを取得できるかどうかを確認する必要があります。最初にロックを取得した MDB が優先され、その MDB のみがメッセージを受信するために登録されます。これで、シリアル化が完了しました。このロックはどのような形を取るべきですか? 多くの可能性があります。さて、これはどうでしょう。データベースにアクセスできる場合は、そのトランザクション ロックによって、必要なものの一部が既に提供されています。1 行のテーブルを作成します。行には、現在ロックを保持しているサーバーの識別子と有効期限があります。これはサーバーのリースです。各サーバーには、一意の識別子 (サーバー名とスレッド ID など) を生成する方法が必要です。
サーバーが行への更新アクセスを取得でき、リースの有効期限が切れている場合は、それを取得する必要があります。そうでなければ、あきらめます。リースを取得した場合は、近い将来の時刻 (5 分程度など) で行を更新し、更新をコミットする必要があります。アクティブ サーバーは、期限が切れる前にリースを更新する必要があります。残り時間が半分になったときに更新することをお勧めします。つまり、リースが 5 で期限切れになる場合は 2.5 分ごとです。これで、フェイルオーバーができました。アクティブな MDB が停止すると、別の MDB (1 つだけ) が引き継ぎます。
それはかなり簡単だと思います。ここで、休眠状態の MDB にロックをときどきチェックさせて、ロックが解放されているかどうかを確認する必要があります。
したがって、アクティブな MDB と休止状態の MDB はすべて、定期的に何かを行う必要があります。これを行うために、別のスレッドを生成させることができます。多くのアプリケーション エンジン ベンダーは、これを行うと満足しませんが、スレッドを 1 つ追加することは大したことではありません。もう 1 つのオプションは、多くのエンジンが提供するタイマー メカニズムに結び付けて、リースをチェックするために定期的に MDB を起動させることです。
ところで、サーバー管理者が NTP を使用して時計を適切に同期させていることを確認してください。