Zookeeper+Norbert を使用して、稼働しているホストと停止しているホストを確認します。
http://www.ibm.com/developerworks/library/j-zookeeper/
これで、チャットルーム サーバー ファーム内のすべてのノードが、論理クラスター内のすべてのホストを認識できるようになりました。ノードがオフラインになる (またはオンラインになる) と、コールバックを受け取ります。どのノードも、現在のクラスター メンバーのソートされたリストを保持し、チャットルーム ID をハッシュし、リスト サイズで変更して、特定のチャットルームをホストするノードであるリスト内のインデックスを取得できるようになりました。1 を追加して再ハッシュして 2 番目のインデックスを選択し (新しいインデックスを取得するまでループが必要)、2 番目のホストを計算して、冗長性のためにチャットルームの 2 番目のコピーを保持できます。2 つのチャットルーム ホストのそれぞれにチャットルーム アクターがあり、チャットルーム メンバーである各 Websocket アクターにすべてのチャット メッセージを転送します。
これで、アクティブなチャットルーム アクターとカスタム Akka ルーターの両方を介してチャット メッセージを送信できるようになりました。クライアントはメッセージを 1 回送信するだけで、ルーターがハッシュ変更を行い、2 つのリモート チャットルーム アクターに送信します。Twitter スノーフレーク アルゴリズムを使用して、送信されるメッセージの一意の 64 ビット ID を生成します。次のリンクで、コードの nextId() メソッドのアルゴリズムを参照してください。異なるサーバーで衝突する ID が生成されないように、norbert プロパティを使用して datacenterId と workerId を設定できます。
https://github.com/twitter/snowflake/blob/master/src/main/scala/com/twitter/service/snowflake/IdWorker.scala
これで、2 つのアクティブなチャットルーム アクターのそれぞれを介して、すべてのメッセージの 2 つのコピーが各クライアント エンドポイントに送信されます。各 Websocket クライアント アクターで、スノーフレーク ID のビットマスクを解除して、メッセージを送信している datacenterId+workerId 番号を学習し、クラスター内の各ホストから見られる最大のチャット メッセージ番号を追跡します。次に、特定の送信者ホストの特定のクライアントで既に見られたものよりも高くないメッセージを無視します。これにより、2 人のアクティブなチャットルーム アクターを介して着信するメッセージのペアが重複排除されます。
ここまでは順調ですね; いずれかのノードが停止した場合でも、生き残ったチャットルームのコピーを 1 つ失わないという点で、回復力のあるメッセージが得られます。メッセージは、2 番目のチャットルームを介して自動的に途切れることなく流れます。
次に、ノードがクラスターから脱落したり、クラスターに追加されたりすることに対処する必要があります。各ノード内で nobert コールバックを取得して、クラスター メンバーシップの変更について通知します。このコールバックで、新しいメンバーシップ リストと現在のホスト名を示すカスタム ルーター経由で akka メッセージを送信できます。現在のホストのカスタム ルーターはそのメッセージを確認し、その状態を更新して新しいクラスター メンバーシップを認識し、特定のチャットルーム トラフィックを送信するための新しいノードのペアを計算します。この新しいクラスタ メンバシップの確認は、ルータによってすべてのノードに送信されるため、すべてのサーバがいつメンバシップの変更に追いつき、メッセージを正しく送信できるようになったかを追跡できます。
生き残ったチャットルームは、メンバーシップの変更後もアクティブである可能性があります。その場合、すべてのノードのすべてのルーターは通常どおり送信を続けますが、新しい 2 番目のチャットルーム ホストにも投機的にメッセージを送信します。その 2 番目のチャットルームはまだ稼働していない可能性がありますが、メッセージはサバイバー経由で流れるので問題ありません。メンバーシップの変更後に生き残ったチャットルームがアクティブでなくなった場合、すべてのホストのすべてのルーターが最初に 3 つのホストに送信します。生存者と2つの新しいノード。akka デス ウォッチ メカニズムを使用すると、すべてのノードが最終的に生き残ったチャットルームのシャットダウンを確認して、2 つのホストを介したチャット トラフィックのルーティングに戻ることができます。
次に、状況に応じて、生き残ったサーバーから 1 つまたは 2 つの新しいホストにチャットルームを移行する必要があります。生き残ったチャットルームのアクターは、ある時点で、新しいクラスター メンバーシップについて知らせるメッセージを受け取ります。チャットルームのメンバーシップのコピーを新しいノードに送信することから始めます。このメッセージは、新しいノードに正しいメンバーシップを持つチャットルーム アクターの新しいコピーを作成します。生存者が、チャットルームを保持する必要がある 2 つのノードのいずれかでなくなった場合、廃止モードになります。廃止モードでは、新しいプライマリ ノードとセカンダリ ノードへのメッセージのみを転送し、チャットルーム メンバーには転送しません。Akka メッセージ転送はこれに最適です。
廃止チャットルームは、各ノードからの norbert クラスター メンバーシップ確認メッセージをリッスンします。最終的に、クラスター内のすべてのノードが新しいクラスター メンバーシップを認識したことがわかります。その後、転送するメッセージをこれ以上受信しないことがわかります。その後、それは自分自身を殺すことができます。Akka ホットスワップは、デコミッション動作を実装するのに最適です。
ここまでは順調ですね; ノードがクラッシュしてもメッセージが失われない、回復力のあるメッセージング設定があります。クラスター メンバーシップが変更された時点で、チャットルームを新しいノードにコピーするためのノード内トラフィックのスパイクが発生します。また、どのチャットルームが 2 つのどのサーバーを移動したかにすべてのサーバーが追いつくまで、ノードへのメッセージのノード内転送の混乱が残ります。システムをスケールアップしたい場合は、ユーザー トラフィックが低下するまで待ってから、新しいノードをオンにするだけです。チャットルームは、新しいノード間で自動的に再分配されます。
上記の説明は、次の論文を読み、それを akka の概念に翻訳したことに基づいています。
https://www.dropbox.com/s/iihpq9bjcfver07/VLDB-Paper.pdf