web-dev-qa-db-ja.com

複数のサーバーへのWebSocketクライアント接続(サーバーではない)のスケーリング

私はWebSocket接続を介してSlackチームに接続する必要があるSlackボットを作成しました。ボットは何千ものチームで使用される可能性があるため、最終的にはチームを複数のサーバーに分散させる必要があります。新しいチームは、初期のOAuth認証を処理するHTTPサーバーを介して追加されます。

私は次のことを達成するのに役立つソリューションを探しています。

  • サーバーが停止または再起動すると、そのサーバーが割り当てられていたすべてのチームを残りのサーバーに再度割り当てる必要があります。 Slackチームがサーバーにすぐに接続される限り、Slackチームへの接続が一時的にダウンしても問題ありません。

  • チームが追加されると、「ビジー」でないサーバーに割り当てられます。 Busyは、現在処理しているチームの数によって簡単に定義できます。

  • これをすべて、最小限のカスタムコードで記述したいと思います。

これまでのところ、私は次の解決策を検討しました:

1) ワークキュー RabbitMQを使用。ボットサーバーは、チームを獲得するために競争します。サーバーがダウンしたときにチームをキューに戻す確実な方法が必要ですが、これは問題ありません。

2)カスタムの「オーケストレーション」サービスを記述します。オーケストレーションサービスは、httpサーバーからチームを受け取り、サーバーのクラスターにチームをディスパッチします。サーバーがダウンしたときと、どのチームを再割り当てする必要があるかを追跡する必要があります。このようなサービスを確実に作成する方法がよくわからないので、これが単一障害点になります。

3)あなたの提案!

2
Olivier Lalonde

基本的に、負荷分散を実現する方法に関するアドバイスを探しています。あなたが提供した制限があっても、これはかなり広いトピックです。

考えられる解決策の1つ:

任意のクライアントが現在アクティブなサーバーのリストを取得するための何らかの手段があるという前提の下で、 Consistent Hashing または Rendezvous Hashing のバリエーションを使用できます。

簡単な例として、各サーバーを0から1の間の多数のランダムなバケット値にマッピングします。特定のクライアントについて、ある種のクライアントID(たとえば、クライアントのIPアドレス)を数値にハッシュし、それをサーバーに送信します選択したサーバーに最も近いバケット[1]

このアプローチにはいくつかの利点があります。

  • サーバーのリストを維持する以外に、このロジックはすべてクライアント側で実行できます。
  • ロジックは信じられないほど単純です。この機能を実装するには、10〜20行のコードしか必要ありません。
  • サーバーの追加または削除は問題なく処理されます。サーバーが追加されると、ほとんどのクライアントはサーバーを切り替えません。サーバーが失われると、そのサーバーのクライアントのみが再マップされます。

このアプローチの欠点は、ランダムであることです。特にクライアントの数が少ない場合、負荷が均等に分散されないリスクがあります。

[1]この計算はラップします(そのため、ほとんどの議論が角度または円について話している理由です)が、これを無視することの影響はかなり小さいです。最も簡単な修正は、1+Min(bucket_value)バケットを追加することです。基本的に、0.01は、バケットの最高値と最低値の偏りを少なくするために、0.5ではなく0.99に近いものとして扱う必要があります。

1
Brian