Web ソケットを使用してクライアントをサポートするサーバーを実装するには、サーバーは各クライアントとの HTTP 接続を開いたままにしますか? これはどのようにスケーリングできますか?
このタイプのサーバーを実装する際の「プログラミング モデル」は何ですか? つまり、ほとんどの Web アプリには、connect->request->response->close タイプ モデルをサポートするサーブレットなどがあります。一方、Web ソケットでは、接続は無期限に開いたままになります。
Web ソケットを使用してクライアントをサポートするサーバーを実装するには、サーバーは各クライアントとの HTTP 接続を開いたままにしますか? これはどのようにスケーリングできますか?
このタイプのサーバーを実装する際の「プログラミング モデル」は何ですか? つまり、ほとんどの Web アプリには、connect->request->response->close タイプ モデルをサポートするサーブレットなどがあります。一方、Web ソケットでは、接続は無期限に開いたままになります。
通常、これらの長期接続が機能するには、非同期モデルで作業する必要があります。非同期 I/O を実行するには、いくつかの異なる手法があります。すべてに長所と短所があります。
JavaScript とAJAXを扱ったことのある人なら誰でも知っているはずのモデルは、コールバック モデルです。リクエストを送信し、完了時に呼び出されるコールバックをインストールします。これはXMLHTTPRequest
、1 つのページの要求が完了するのを待っている間、他のすべてのページをブロックすることなく、どのように機能するかです。これはTwisted Python ネットワーク フレームワークの動作方法でもありますが、使用するインターフェイスに応じて、オブジェクトまたはコールバック関数のメソッドを呼び出すことができます。
もう 1 つの強力なモデルは、アクター モデルと呼ばれるErlangスタイルのアプローチで、非常に多くの軽量プロセス (スレッドに似ていますが、共有状態はありません) があり、それぞれが非同期メッセージを介して相互に通信します。Erlang ランタイムは、何千ものプロセスの生成を非常に効率的にするために実装されています。そうすれば、接続ごとに 1 つのプロセスを作成し、アプリケーションのバックエンドを実装する他のプロセスにメッセージを送信させることができます。Erlang プロセスは、マルチコア システムを最大限に活用するために、複数の OS スレッドで自動的にスケジュールすることもできます。人気のある Jabber サーバーであるejabberd (多くの長時間のオープン接続を必要とするチャット プロトコル) は、Facebook チャット システムと同様に Erlang で実装されています。
Googleの新しいGo 言語は同様のアプローチを使用しており、Erlang の Actor モデルよりも Hoare の Communicating Sequential モデルに近いですが、多くの類似点があります。
Mac OS X 10.6 で、Appleは C、C++、および Objective-C のブロック (本質的にはクロージャ) とともに、Grand Central Dispatchを導入しました。これにより、AJAX または Twisted スタイルのイベント ドリブン コールバック モデルのようなものを使用できますが、マルチスレッド、マルチコア環境で共有リソースへのアクセスを管理するために順次実行される明示的に管理されたキューを使用できます。Twisted と JavaScript はどちらもシングル スレッドで実行されるため、複数のオペレーティング システム プロセスを使用しない限り、1 つのコアしか利用できません。これは、かなりの負荷がかかり、それらの間の通信コストが増加する可能性があります。
次に、Unixselect
機能などのより伝統的なモデル、またはより現代的で機能的なモデルepoll
やkqueue()
. これらでは、通常、プログラムにメインループがあり、監視する一連のイベントを設定します (ネットワーク I/O がさらにデータを返し、ファイル I/O がさらにデータを返し、新しいネットワーク接続が確立されるなど)。を呼び出してから、これらのイベントのいずれかが発生するまでブロックするシステム コールを呼び出します。発生した時点で、どのイベントが発生したかを確認し、適切に処理します。これらのシステム コールは、通常、上記の上位レベルのフレームワークを提供するために使用されます。
利用可能な膨大な数のオプション (より伝統的で低レベルの Unix アプローチに焦点を当てたもの) の非常に優れた概要については、The C10K Problemを参照してください。これには、 libeventなど、利用可能なさまざまな API を抽象化するための C および C++ ライブラリの優れたリストもあります。
もちろん、最後のオプションは、接続ごとに 1 つのプロセスまたは 1 つの OS スレッドを使用することです。問題は、これらのオプションの多くと比較して、プロセスが非常に重く、スレッドでさえかなり重いことです。一般に、最高のパフォーマンスを得るには、CPU ごとに 1 つのプロセスまたはスレッドを用意し、それぞれが非同期 I/O API を使用していつ作業を行う必要があるかを判断し、その作業をいくつかのオブジェクトまたはコールバックの 1 つにディスパッチします。接続を処理するために登録されているもの、またはメッセージを待機しているいくつかの Erlang スタイルの軽量プロセスの 1 つ、またはそのようなものです。
補足として、Web ソケットの接続は HTTP 接続ではなく、新しいプロトコルであるwebsocket プロトコルですが、HTTP と同じポートを使用し、HTTP 接続を Web ソケットにアップグレードして、既存の接続と互換性を持たせることができます。ファイアウォール ルール。
一般的に言えば、軽量な方法で負荷を処理するように設計されたカスタム サーバー実装で WebSocket を使用することを期待する必要があります。そのようなサーバーは、長寿命の COMET 接続などのためにすでに存在します。
後続の各要求/応答を http ヘッダーを含む http メッセージにラップする必要がないという点で、http とは異なります。そのため、リアルタイム アプリはヘッダーを解析するオーバーヘッドを必要としません。最初の http のようなハンドシェイクの後、基本的には通常の古い tcp ソケットのように動作します。
これはサーブレットでモデル化できますが、最初の要求 (すべてのヘッダーを含む) と、ほとんどの場合フォーマットが任意である後続の双方向ダイアログを区別する必要があるだけです。
Tornado Web サーバーに実装されている HTML 5 WebSocket をご覧ください: http://bret.appspot.com/entry/web-sockets-in-tornado
ただし、私はまだこのモジュールで遊んでいません。