これはプロトタイプです。物事を報告し、コマンドを待機するwebsocketを介してサーバーに接続された100クライアントのプールがあります。サーバーは、_WHERE client_id=?
_を使用したクエリを使用して、ループでcommands
タイプのMEMORY
データベーステーブルをポーリングします。 _client_id
_ + command
の組み合わせをそのテーブルに挿入できます。これを実行すると、対応するループが一致してSELECT
となり、それをクライアントに返します。
このアプローチはうまくいくように聞こえますが、私が理解している限り、エンドレスループ(n
はクライアントの数です)でのn
同時データベース接続とクエリについて話しています。効果的に聞こえません。 1つのループで1つのクエリを実行してから、もしあれば_client_id
_をチェックして、対応するクライアントに結果を配布する方がはるかに良いでしょう。
これは、最初に記事を選択し、次に結果セットをfor () {}
にして、個別のクエリを実行して各項目の詳細を取得するというアプローチを思い出させます。その結果、_n+1
_クエリが実行されます。その解決策は、JOIN
sで大きなクエリを実行し、メインのJOIN
edクエリに適合しない他のデータをプリロードすることです。データベースのポーリングを行うための同様のより効果的な方法があるはずです。
[〜#〜] update [〜#〜]:関連セクションに this answer が見つかりました。ほぼ同じこと:
データベースを叩くことは本当に良い考えではありません。あなたがこれに気付いたと私は確信していますが、他の人はそうではないかもしれません。私の友人がPHPスクリプトとJavascript AJAX関数をループでセミリアルタイムゲームに使用しようとしたことを覚えています。彼はすぐに、データベースを破壊する1秒間に大量のクエリを実行していたため、より多くの人が参加するとパフォーマンスが低下することをすぐに理解しました。
したがって、各クライアントのデータベースをポーリングすることは、AJAXチャットアプリケーションを構築するのと同じくらいスケーラブルでなく、効果がありません。
考えられるすべてのプログラミング手法は、今では名前が付けられてカバーされているに違いないので、これは何と呼ばれていますか?ここでの一般的なアドバイス/アプローチは何ですか?
接続プールが必要-100個のクライアントが少数のDB接続のプールを使用するように調整されるため、DBが多数の同時リクエストに応答して過負荷にならないようにします。
呼び出しを最適化することもできますが、クライアントが接続プールと同じメカニズムを介してDBにアクセスできるようにする必要があります。プールで使用できる接続が1つしかない場合でも、保留中のすべてのIDを組み合わせることができます。クライアントを1つのwhere句にまとめてDBに渡し、返されたときに結果を各クライアントにアンパックします。リクエストに含まれるクライアントを追跡するか、DBクエリの進行中にさらに多くのクライアントが到着するので、リクエストしている各クライアントの結果が結果にあることを確認する必要があります。結果がクライアントに配信されると、新しいもの。
このようなプールがあり、状況に応じて許容できる場合は、DBリクエストを緩やかな速度で遅らせることもできますが、単一の接続でDBを繰り返しヒットしても、100クライアントほどのパフォーマンスが影響を受けることはありません。同時に。
間違った質問をしました。正しい質問は"データベーステーブルを使用してキューを実装する必要がありますか?"と答えは[〜#〜 ]いいえ[〜#〜]。 Kafkaのような堅牢な分散キューイング実装を使用します。
または、データベースにキューイングメカニズムが組み込まれている場合があります。オラクルはそうします。 Tom Kiteは、データベーステーブルをキューとして使用してはならない理由を説明したOracleの本の1冊に1ページまたは2ページを費やしています。
理想的には、データベースへの書き込みが発生したときに、(http要求または他の回答で述べたキューメカニズムを介して)WebSocketサーバーにプッシュする必要があります。これにより、データベースのポーリングを完全に回避できます。
データベースを使用する以外に方法がない場合は、1つのクエリを実行して、すべてのクライアントの情報を取得します。これは、ループ内でクエリを記述することを回避するのに役立ちます。アプリケーションでは、各クライアントのデータを分離して、WebSocketを介して送信できます。
クライアントが発行する必要があるクエリが複雑でない限り、ここではSQLデータベースを使用しません。メモリテーブルを使用している場合でも、かなりのオーバーヘッドがあります。プロセス間通信、クエリの解釈、必要のないクエリタイプ(範囲など)をサポートするインデックスの維持、データのマーシャリングなど。
正確にどのようにするかは、アプリケーションの他の要件に大きく依存します。複数のサーバーにスケーリングする必要がない場合は、インプロセスストア(つまり、共有変数のJavaScriptマップ)がデータを共有する最も効率的な方法です。それ以外の場合は、インメモリキーバリューストアデータベースを調べます。 redis。
とりわけ、私はデータアクセスを抽象化して、後でこれらのオプションを簡単に変更できるようにします。
IMO、ほとんどすべてを自分ですでに理解しています...私のお気に入りのフレームワークがこのようなものに使用するパターンの種類について詳しく説明します。
最初に、クライアントがコマンドにサブスクライブするようにします。これにより、サーバーは、どのソケット(クライアント)がどのclient_idに関連付けられたコマンドを必要としているかを認識します。サーバーはデータベースをポーリングし、X秒(ミリ秒?)ごとにORはoplog tailing *を使用して実行するコマンドがあるかどうかを確認し、ある場合は、そのコマンドをターゲットclient_idに従ってサブスクライブするソケットに送信します。 ...
* oplogテーリングはレプリカセットで使用され、データベースで行われたすべての操作のログです。データベースを直接プールするよりも、テーリングする方が効果的です...新しいドキュメントがいつ挿入されたかを知るためにテールを使用してから、データベースをクエリする必要があることを知ると、大規模なセットの負荷が低くなりますが、必要ない場合もあります。