同時サーバー要求を処理するには2つの方法があります。 ストリーミング(スレッド、同期)サーバーは、同時に実行される多数のスレッドを使用し、それぞれが1つの要求を処理します。 この時点で、イベント(イベント、非同期)サーバーは、すべての要求を処理する単一のイベントループを実行します。
2つのアプローチのいずれかを選択するには、サーバーの負荷プロファイルを決定する必要があります。
各リクエストの処理に
cミリ秒のCPUと
wミリ秒のリアルタイムが必要であるとします。 CPU時間はアクティブコンピューティングに費やされ、リアルタイムには外部リソースへのすべてのリクエストが含まれます。 たとえば、リクエストにはCPUからの時間
cが5ミリ秒、データベースからの応答を待つのに95ミリ秒が必要です。 結果は100msです。 また、サーバーのストリーミングバージョンが、スケジューリングとコンテキストスイッチングの問題が始まる前に最大
tスレッドをサポートできると仮定します。
各リクエストの処理にCPU時間のみが必要な場合、サーバーは1秒あたり最大で1000 /
cリクエストに応答できます。 たとえば、各リクエストに2ミリ秒のCPU時間がかかる場合、1000/2 = 500リクエスト/秒になります。
一般に、マルチスレッドサーバーは、1秒あたり
t * 1000 /
w要求を処理できます。
ストリーミングサーバーの帯域幅は、これらの式の最小値です(1000 /
cおよび
t * 1000 /
w )。 イベントサーバーは1つのスレッドのみを使用するため、CPUパフォーマンス(1000 /
c )によってのみ制限されます。 上記のすべては、次のように表現できます。
def max_request_rate(t, c, w): cpu_bound = 1000. / c thread_bound = t * 1000. / w print 'threaded: %d\nevented: %d' % (min(cpu_bound, thread_bound), cpu_bound)
次に、さまざまな種類のサーバーを検討し、さまざまな実装でそれらがどのように表示されるかを確認します。
例として、
t = 100を使用します。
古典的な例であるHTTPプロキシサーバーから始めましょう。 このタイプのサーバーはCPU時間をほとんど必要としないため、
c = 0.1 msと仮定し
ます 。 隣のサーバーが遅延、たとえば
w = 50ミリ秒を受信するとします。 それから私達は得る:
>>> max_request_rate(100, 0.1, 50) threaded: 2000 evented: 10000
計算では、ストリーミングサーバーは1秒あたり2,000リクエスト、イベントサーバーは10,000リクエストを処理できることが示されています。イベントサーバーの高いパフォーマンスは、ストリーミングサーバーのスレッド数がボトルネックになったことを示しています。
別の例は、Webアプリケーションサーバーです。 まず、外部リソースを必要としないが、特定の計算を実行するアプリケーションの場合を考えます。 処理時間は、たとえば5ミリ秒です。 なぜなら ブロッキング呼び出しは行われません。時間
wも5ミリ秒になります。 次に:
>>> max_request_rate(100, 5, 5) threaded: 200 evented: 200
この場合、CPUパフォーマンスがボトルネックになりました。
ここで、アプリケーションが外部リソースからデータを要求する必要があり、CPU時間は0.5ミリ秒であり、合計時間
w = 100ミリ秒であると想像してください。
>>> max_request_rate(100, 0.5, 100) threaded: 1000 evented: 2000
単純な計算から、そして実際に数学からわかるように、同期ストリーミング実装は非同期イベント実装よりも優れたパフォーマンスを発揮しません。
ただし、エンドユーザーは主に、応答を待つために費やしているリアルタイムに関心があることを考慮する価値があります。 問題は、アプリケーションが何かをしなければならないときに始まります。 たとえば、データベースに対して大規模で複雑なリクエストを作成し、複雑な計算を実行し、グラフィックを処理し、他の誰かのサーバーにリクエストを作成します。 多くの例があります。
たとえば、1サイクルで1万人のクライアントにサービスを提供するシングルスレッドプログラムが1秒間、たとえば1秒間待機する必要があると、すぐに他の全員がこの秒を待機します。 そのような要求が多数ある場合、単一のクライアントは、要求を処理する合計時間よりも早く応答を受信しません。 動作中の協調マルチタスク。 ストリーミングソリューションの場合、プリエンプティブマルチタスクが有効です。 システムは、すべての時間を無駄にする「重い」要求を許可しません。
一方では、既存のライブラリのほとんどがブロッキングスタイルで記述されているため、非同期ソリューションが豊富にあり、そのボトルネックはプログラムの作成の難しさです。 プログラマーは、1つの要求のエラーが残りに影響を与えないという事実に責任を負います。
一方、プログラムの作成に慣れているブロッキングソリューションがあります。 サポートされているスレッド数の問題は、greenletやErlangプロセスなどの専用ツールを使用して解決できます。 ストリーミングサーバーがスレッド数がボトルネックになるのをやめるレベルに達すると、応答時間と信頼性のためにより魅力的に見えます。