sgcWebSockets 2024.2.0 から、HTTP/2 サーバーは HTTP/2 リクエスト受信時の処理が改善されました。デフォルトでは、サーバーが新しい HTTP/2 リクエストを受信すると、スレッドプール内のスレッドの 1 つにキューイングされて処理されます。これにより、同じ接続を使って複数のリクエストが送信され、それらが順次処理されてしまう問題を回避できます。
以下に HTTP 1.1 と HTTP 2.0 の違いを示します。
HTTP 1.1
従来の HTTP の動作では、同じ接続上で複数のリクエストを行う場合、クライアントは各リクエストのレスポンスを待ってから次を送信する必要があります。この逐次処理アプローチは、Web サイトのリソースの読み込み時間を大幅に増加させます。この問題に対処するため、HTTP/1.1 では パイプライニング という機能が導入され、クライアントがサーバーのレスポンスを待たずに複数のリクエストを送信できるようになりました。サーバーは、リクエストを受信した順序と同じ順序でクライアントに応答します。
パイプライニング は解決策と思われましたが、次のような課題に直面しました。
- サーバーによる無視またはレスポンスの破損: 一部のサーバーは パイプライン化 されたリクエストを無視するか、レスポンスを破損させ、信頼性の低い通信を招きました。
- Head-of-Line ブロッキング: パイプラインの最初のリクエストが後続のリクエストをブロックし、他のリクエストの処理に遅延を生じる可能性があります。この現象は Head-of-Line ブロッキングとして知られ、ページの読み込み時間の遅延につながりました。
HTTP/1.1 対応サーバーからのページ読み込みを最適化するため、Web ブラウザーは回避策を実装しました。サーバーに対して 6〜8 本の並列接続を開き、複数のリクエストを同時に送信できるようにします。この並列化により、パイプライニング に関連する問題を緩和し、全体的なページ読み込み時間を改善することを目指しています。
Web ブラウザーが 6〜8 本の並列接続を選択しているのは最適化上の考慮に基づいています。この数を選択する具体的な理由には、リソース使用率、ネットワーク効率、潜在的なボトルネックの回避の間のトレードオフが含まれる可能性があります。
HTTP 2.0
パイプライニング で直面した制約に対処するため、HTTP/2 はマルチプレクシングという機能を導入しました。マルチプレクシング は、単一の接続上で 複数のリクエスト とレスポンスの 同時送信 を可能にすることで、クライアントとサーバー間の より効率的な通信 を実現します。
HTTP/2 はバイナリフレーミングという仕組みを利用しており、HTTP メッセージはフレームと呼ばれるより小さく独立した単位に分割されます。これらのフレームは互いに独立してインターリーブされ、接続上に送信されます。受信側でフレームが再構成され、元の HTTP メッセージが復元されます。
このバイナリフレーミングの仕組みは、HTTP/2 におけるマルチプレクシングの実現に不可欠です。これによりブラウザーはブロッキングの問題に遭遇することなく、同じ接続上で複数のリクエストを送信できます。その結果、Chrome のようなブラウザーは HTTP/2 リクエストに同じ接続 ID を利用し、クライアントとサーバー間の効率的かつ中断のない通信を可能にします。
要するに、バイナリフレーミングの仕組みにより実現される HTTP/2 のマルチプレクシング機能は、単一の接続上で複数のリクエストとレスポンスの同時送信を促進することにより、クライアントとサーバー間のデータ交換の効率と速度を向上させます。
TsgcWebSocketHTTPServer コンポーネント
HTTP/2 プロトコルのパフォーマンスを向上させるため、サーバーが新しい HTTP/2 リクエストを受信するたびに、リクエストはデフォルトでスレッドプール(デフォルト 32)で処理されます。これにより、単一の接続が多数の同時リクエストを送信し、スレッドプールがない場合に(接続スレッドのコンテキストで)順次処理する必要が生じる際の待機を回避できます。
PoolOfThreads の 動作 は、以下のプロパティで設定できます。
- HTTP2Options.PoolOfThreads.Enabled:(デフォルト true)接続スレッドではなく、スレッドプールで HTTP/2 リクエストを処理できるようにします。
- HTTP2Options.Threads:(デフォルト 32)HTTP/2 リクエストの処理に使用するスレッド数。サーバーのプロセッサー数に応じて値を設定してください。
スレッドプールで処理するもの(時間がかかるため)と、接続スレッドで処理できるものを リクエスト単位で細かく調整 するには、OnHttp2BeforeAsyncRequest イベントを使用できます。このイベントはリクエストをスレッドプールにキューイングする前に発生します。Async パラメーターを使ってリクエストをスレッド化するかどうかを設定してください。
procedure OnHTTP2BeforeAsyncRequest(Sender: TObject; Connection: TsgcWSConnection; const ARequestInfo: TIdHTTPRequestInfo; var Async: Boolean);
begin
if ARequestInfo.Document = '/time-consuming-request' then
ASync := False;
end;
