web-dev-qa-db-ja.com

ユーザーステータスを効率的にブロードキャストする

これは私の予想に反してかなり興味深い問題であることが判明しました。

簡単なチャットアプリを想像してみてください。ユーザーが登録すると、他のユーザーを連絡先リストに追加して会話を開始できます。

各ユーザーのオンラインステータスをリアルタイムで表示できるようにしたい(簡単にするために、オンライン/オフラインのみ)。問題は、それを効率的に行う方法です。

アプリはWebSocketを利用するため、サーバー上に接続のリストがあり、タスクが簡単になります。最も明白な解決策は、ユーザーが接続または切断するたびに、それを他のすべてのユーザーにブロードキャストすることです。連絡先リストにトリガーとなるユーザーがいないすべてのユーザーは単に気にしないため、これは明らかにあまり効率的ではありません。ユーザー数が多い場合は、無駄な帯域幅も気になります。

より最適化された解決策は、接続しているユーザーに連絡先リストの全員のステータスを尋ねさせることです。次に、サーバー上の各ユーザーのリストを作成し、ステータスを要求したすべてのユーザーのIDを保存します。このようにして、ユーザーが接続/切断するたびに、これを気にするユーザーのリストが表示され、無駄がないことを認識してイベントをブロードキャストできます。ただし、これについて私が気に入らないのは、スキームにかなりの複雑さが追加されていることと、そのようなリストをサーバーに保持すると、ユーザーの数に比例して使用されるメモリの量が増えることです(常にそうですが、そのようなタスクには多すぎるようです)。

チャットアプリは新しいものではないので、既存のアプリでそのような機能に使用される方法は何か、またはよく知られている特効薬の解決策があるかどうかを尋ねたいと思います。

1
php_nub_qq

接続/切断イベントは非常にまれである可能性が高いため、これを過度に最適化することはあまり意味がありません。特に、切断はタイムアウトによって発生することがよくあります。そのステータス変更が数秒後にブロードキャストされる場合、これは問題ではありません。

重要なのはプライバシーへの影響です。すべてのユーザーにステータスをブロードキャストするのではなく、

  • 誰がステータスを見ることができるか、そして
  • そのステータスに興味がある人。

これらのグループの共通部分にのみ通知を送信する必要があります。たとえば、連絡先リストのすべての人が私のステータスの変更を確認できます。私が連絡先リストにも含まれていて、オンラインである場合にのみ、人々は私のステータスに興味を持っています。現在のステータスと連絡先リストを、適度に複雑なSQLクエリ(2つの結合)で確認できるデータベースに保存する場合。ただし、適切なインデックスがあれば、このクエリは大規模なユーザーベースでも非常に高速です。

一部のチャットアプリケーションは、すべての連絡先のステータスを表示しません。例えば。 WhatsAppユーザーインターフェイスは、その人との1:1チャットでのみこのステータスを表示します。つまり、ステータスの変更によってトリガーされる通知はごくわずかであり、おそらくまったくトリガーされません。しかし、あるユーザーから別のユーザーのステータスへの明示的なサブスクリプションの観点から、これについて考える方が簡単です。これらのサブスクリプションを維持するには、開いているソケットのコストと比較して、必要なメモリはごくわずかです。

1
amon