Indy サーバー — IOCP Windows(2 / 3)

· 機能

sgcWebSockets 2022.9.0 から、Indy サーバーの IOCP IOHandler はゼロから書き直され、パフォーマンスが向上しました。IOCP IOHandler は sgcWebSockets Enterprise パッケージでのみ利用可能です。

IOCP を使用すると、サーバーが処理する接続数が増えるとパフォーマンスが大幅に低下する 「クライアントごとに 1 スレッド」 の問題を回避できます。IOCP は複数のクライアントを扱う少数のスレッドを提供します。スレッドは中断され、処理すべきものがあるまで CPU サイクルを消費しません。

設定 

Indy サーバーで IOCP を有効にするには、IOHandlerOptions プロパティに移動し、IOHandler Type として iohIOCP を選択します。 

Server.IOHandlerOptions.IOHandlerType := iohIOCP;
Server.IOHandlerOptions.IOCP.IOCPThreads := 0; // the number of IOCP threads will be calculated automatically using the number of processors.
Server.IOHandlerOptions.IOCP.WorkOpThreads := 0; 

1. IOCPThreads は IOCP 非同期リクエスト(オーバーラップド操作)に使用されるスレッドです。デフォルト値はゼロで、これはプロセッサー数を使って自動計算されることを意味します(Delphi 7 と 2007 では cpucount 関数がサポートされないため 32 に設定されます)。

2. WorkOpThreads は、接続を常に同じスレッドで処理したい場合のみ有効にする必要があります。IOCP を使用する場合、リクエストはスレッドプールで処理され、(同じ接続の)各リクエストは異なるスレッドで処理される可能性があります。すべての接続を同じスレッドで処理したい場合は、WorkOpThreads にこれらのリクエストの処理に使用するスレッド数を設定してください。これはサーバーのパフォーマンスに影響するため、この機能が必要な場合のみゼロより大きい値を設定することが推奨されます。

Windows サーバーで IOCP を有効にすることが推奨されるのは、数千の接続を処理する必要がある場合です。サーバーが最大 100 個の同時接続のみを処理する場合は、デフォルトの Indy スレッドモデルのままでも問題ありません。

Performance Test 

シンプルなテストで Indy スレッドモデルと IOCP の違いを示します。テストでは websocket プロトコルを使用してサーバーに接続し、CPU 使用率とメモリ消費量を以下の表に示します。CPU 使用率はサーバーがアイドル状態のときの値です。

接続数 Indy デフォルト IOHandler Indy IOCP IOHandler
100 0% (4.1MB) 0% (3.9MB)
5000% (17.1MB)0% (7.7MB)
10000% (32.2MB)0% (12.4MB)
15007.3% (46.8MB)0% (17.1MB)
200015.4% (61.6MB)0% (21.9MB)
250051.9% (76.5MB)0% (26.5MB)
300068.8% (91.7MB)0% (31.2MB)
350072.3% (106MB)0% (35.9MB)

Indy サーバーは 3000 を超える同時接続で速度低下が発生し始めました。これはおそらくスレッドコンテキストスイッチが原因で、サーバーがアイドル状態のときにも CPU 使用率が非常に高くなりました。

IOCP サーバーはアイドル状態のときに CPU を使用せず、メモリ消費量もより低いものでした。

次のテストでは、3000 個のクライアントの接続にかかる時間を測定します。各クライアントはサーバーに接続したときにメッセージを送信し、サーバーはそのメッセージをエコー返信します。

Indy デフォルト IOHandler Indy IOCP IOHandler
3000 クライアントを接続してメッセージをエコー 15.32 seconds 6.89 seconds

パフォーマンステストは、16 コア・RAM 32GB の Windows Server 2022 で実施しました。