してみるテストロゴ
Apache 2.4系でHTTP/2サーバを構築してみるテスト。

mod_http2のリファレンス

mod_http2のリファレンスです。

公式の英語リファレンスを元に、わたしなりの解釈をいれて解説しています。

間違いなどございましたら、ツイッター経由でご指摘いただければ嬉しいです。

http/2ストリームの設定

HTTP/2には、複数のファイルを同時にダウンロードできる仕組みがあります。

これはストリームと呼ばれる区分ごとに、異なるファイルを送信することで実現しています。

ストリームひとつが、HTTP/1.1の1接続分のような感じです。

ストリームが多ければ、同時に多数のファイルをダウンロードできますが、必要となるメモリも増えます。

H2MaxSessionStreams

HTTP/2(TCP)接続あたりのストリーム数を指定します。

同時に並行してクライアントに送信できるファイルの数の目安になります。

デフォルト100ですが、メモリーを節約するために、15~20程度で良いでしょう。

1ストリーム当たり、最大、H2StreamMaxMemSize(デフォルトで64Kバイト)のメモリが割り当てられます。

つまりデフォルトのままでは、1接続当たり、最大6.4Mのメモリを割り当てることになります。

仮に、H2MaxSessionStreamsを15にすれば、1接続当たり、最大1Mバイトのメモリに収まります。

この設定は、バーチャルホスト毎に設定できます。

H2MaxSessionStreams 15

H2OutputBuffering

[httpd 2.4.47以降]

HTTP/2接続の出力バッファリングの有無を指定します。

デフォルトで、出力バッファリングは有効です。(H2OutputBuffering on)

出力バッファリングをoffとすると、直ちにデータはクライアントに送信されます。これにより、gRPCの相互運用の問題が解消します。

ワーカスレッドの設定

H2MaxWorkerIdleSeconds

利用されていないワーカスレッドは、このディレクティブで指定された秒数を経過すると終了します。

これは、 ワーカスレッド数が、H2MinWorkersの数を超えているときに使用されます。

H2MaxWorkerIdleSeconds 60

H2MaxWorkers

プロセスあたりのワーカスレッド数の最大数。

このディレクティブが設定されなければ、mpmモジュールの適合する値、たとえば ThreadsPerChild.を利用します。

プロセスあたりのファイルディスクリプタの最大値(Apacheの場合は65535)の場合、

(h2_connections × extra_files) + (h2_max_worker) <= ( 65536 - h2_connections[=socket利用分])

を満たすように調整します。

H2MaxWorkers 256

H2MinWorkers

プロセスあたりのワーカスレッド数の最小数。

このディレクティブが設定されなければ、mpmモジュールの適合する値、たとえば ThreadsPerChild.を利用します。

H2MinWorkers 5

メモリやファイルハンドルなどのリソース設定

H2SessionExtraFiles

ひとつのHTTP/2接続あたり、利用できるファイルハンドルの数を指定します。

一般に、ファイルハンドルは、静的ファイルをメモリにロードする際に利用します。

1接続あたりのファイルハンドルが多ければ、コネクション数の増加に伴い、プロセスの制限に到達してしいますが、十分な数のファイルをメモリに読み込めるため、応答が素早くなります。

HTTP/2が利用するファイルハンドルの数は、

(h2_connections × extra_files) + (h2_max_worker)

と求められます。

apachectlを利用して起動している場合は、apachectlに、

ULIMIT_MAX_FILES="ulimit -S -n `ulimit -H -n`"

とあれるので、たいていのOSはファイルディスクリプタ注:ファイルハンドルではありません!)を65536個利用できるようになっているはずです。

極端な話、このうち、httpdが、socket等に利用するファイルディスクリプタの分を引いた数を、ファイルハンドルに割り当てることができます。

つまり、

(h2_connections × extra_files) + (h2_max_worker) <= ( 65536 - h2_connections[=socket利用分])

を満たすようにします。

実際には、他のモジュールなども絡むでしょうから

(h2_connections × (extra_files + 3) + (h2_max_worker×3) <= ( 65536 - h2_connections[=socket利用分]×2)

あたりの、おとなしめにするといいと思います。

巨大なファイルを複数並行して配信する場合は、ファイルハンドルが占有されがちなので、多めにしておくといいでしょう。

H2MaxSessionStreamsを超える必要は無いでしょう。

この設定は、バーチャルホスト毎に設定できます。

H2SessionExtraFiles 10

H2StreamMaxMemSize

ストリームあたりの送信バッファが利用する、最大のメモリ使用量をバイト単位で指定します。

HTTP/2全体の送信バッファの、メモリの使用量の最大値は、以下の計算式で求まります。

h2_connections × H2MaxSessionStreams × H2StreamMaxMemSize( デフォルトは65536バイト)

たとえば、100接続、1接続当たり20ストリーム、1ストリーム最大65536バイトだと、最大131Mバイトのメモリを利用します。他のメモリー使用量と併せて、ディスクスワップが発生しない量のメモリー使用量となるように設定します。

送信するHTMLファイルやCSSファイルの、大多数が収まるサイズにしておくと、ファイルハンドルの解放が速くなるので、H2SessionExtraFilesを増やさなくて済みます。

逆に、H2MaxSessionStreamsのサイズに、収まらないと、ファイル全体を送信バッファに読み込むまで、ファイルハンドルが解放されないので、ストリームの数が多くても、H2SessionExtraFilesにある数以上のファイルを並列して送信できなくなります。

そこで、大きなファイルを送信する場合は、これを大きくして、H2MaxSessionStreamsを小さめにするといったチューニングになるでしょう。

この設定は、バーチャルホスト毎に設定できます。

H2StreamMaxMemSize 131072

H2WindowSize

クライアントからのアップロード方向のフローコントロールのWindowサイズを指定します。

デフォルトで65535バイトです。 1024以下の値を設定すると、1024になります。

クライアントの送信したデータがこのサイズに到達すると、サーバがこのデータを処理できる領域に移動したとアナウンスするまで、クライアントは送信を一旦止めます。
 この制限は、リクエスト本体にのみ影響します。レスポンス本体には影響しません。

リクエストのサイズは、GETメソッドのパラメータや、その他リクエストヘッダの合計ですが、1リクエスト512バイトを超えることはそうないと思われます。

 あとは、同時に処理できるストリーム以上は、必要無いので、

H2MaxSessionStreams×512バイト

 といった計算式で求めた値で、メモリを節約するのもいいでしょう。

 大体10Kバイトもあれば十分でしょうか。

H2WindowSize 8192

H2CopyFiles

(Apache2.4.24以降)

リクエスト中にファイルがコピーされ、そのデータが、メイン接続に渡されます。

モジュール(例えばmod_wsgi)によっては、異なる寿命のファイルを応答に利用するため、有用ですが、I/Oオーバヘッドがあります。

デフォルトでOffです。

H2CopyFiles On

TLS関連の設定

H2ModernTLSOnly

on(デフォルト)の場合、RFC7540のブラックリストにリストアップされた暗号スイートを利用しません。

これらは、基本的に、前方秘匿性の無い暗号スイートです。

前方秘匿性については、こちらをご覧ください。

offにすると、脆弱性などを含む暗号スイートを利用する可能性があるので、onのままを推奨します。

H2ModernTLSOnly on

H2TLSCoolDownSecs

このディレクティブは、H2TLSWarmUpSizeで指定されたデータ量を送信して、TLSの送信レコードサイズが16Kバイトになっている際に影響します。

TLSの送信レコードサイズを 1300バイト以下(MTUレベル)の長さの小さいものに戻すまでの秒数を指定します。

この間のTLS送信がなければ、送信レコードサイズを 1300バイト以下に戻します。

0なら、戻しません。

デフォルトは1秒です。

イントラネットなど、有線の安定したネットワークなら0を設定したいところですが、スマホなどの無線区間のある相手なら、通信状況が刻一刻と変わります。

ということで、デフォルトのままでもいい気もします。

大きめのファイルを送信することが多い場合も、3秒程度、送信できなければ、通信状況が変化したと判断して、クールダウンするのがいいでしょう。

H2TLSCoolDownSecs 1

H2TLSWarmUpSize

TLSの送信レコードサイズが1300バイト以下のときに、このディレクティブに指定されたデータ量を送信すると、TLSの送信レコードサイズを16Kバイトにします。

TCPが、フローコントロールや、ウィンドウサイズを調整している間は、TLSの送信レコードサイズをMTUレベルの1300バイト以下にします。

フローコントロールやウィンドウサイズの調整の最中は、パケットロスの可能性があり、その場合、再送の必要があります。

このときの再送のロスが大きくならないように、TLSのレコードサイズも、MTUレベルに抑えておきます。

十分なバイト数を送信すると、TCP接続の状況が安定し、TLSレコードサイズを最大の16Kバイトにして、最適なパフォーマンスを利用することができます。

デフォルトは、1048576です。1Mバイトも転送しないと、TLSレコードサイズが増えません。これでは、ほとんどの場合、増えない気がします。

初期のウィンドウサイズの調整は、MTUレベルのパケットを50回くらい送れば、十分でしょう。

ということで、64Kバイトあたりをお試しいただくといいかもしれません。

H2TLSWarmUpSize 65536

H2Push関連の設定

H2Push

HTTP/2 サーバプッシュプロトコル機能を使用します。

デフォルトでonです。

以下のように、依存元ファイル(index.html)ごとに、プッシュする、依存先ファイル(style.css)を指定します。

H2Push on
<Location /index.html>
    Header add Link "</style.css>;rel=preload"
</Location>

詳細は、チューニングをご覧ください。

H2PushDiarySize

接続毎に、プッシュしたURLを記憶する数を指定します。

これに記憶されていれば、一度プッシュされているので、同一接続において、プッシュしなくなります。

デフォルトで256URL分(1エントリ8バイトなので、1接続あたり2Kバイトを割り当て)記憶します。

接続が切れればリセットされます。

この恩恵を受けるには、KeepAliveは長目が望ましいです。

たいして容量を消費するわけではありませんが、手作業で Header add Link ~を追加しているのであれば、32もあれば十分でしょう。

H2PushDiarySize 32

H2PushPriority

H2PushPriorityディレクティブは、コンテンツタイプ毎に、優先度をつけて、送信順序を調整します。

依存元ファイルよりも、早めに送信した方が良いコンテンツタイプに、優先的に送信順序や、帯域を割り当てましょうというのが、このディレクティブです。

デフォルトは、

H2PushPriority * After 16

となっています。

詳細は、チューニングをご覧ください。

H2PushPriority text/css Interleaved 256

H2PushResource

(Apache2.4.24以降)

H2PushResourceディレクティブは、プッシュ対象のディレクトリ(Directory)やロケーション(Location)を追加します。

これは、 Header add Linkを使用した場合よりも早くプッシュできます。

構文は、以下の通りです。

H2PushResource [add] path [critical]

このディレクティブは、linkヘッダを使ったものとは異なり、HTTP/2接続のみ有効です。

criticalオプションをつけると、優先度を高めて送信します。この場合、パス(path)の前にaddをつけてください。

H2EarlyHints

(Apache2.4.24以降)

Onにすると、103 Early Hintsレスポンスを返します。

これにより、クライアントは、より早く、サーバからのプッシュされる予定のファイルを知ることができるため、余計なリクエストを減らせるかもしれません。

103 Early Hintsレスポンスを返すのは、H2PushResourceディレクティブで指定されたパスと、 Header add Link の両方です。

H2EarlyHints on

その他の設定

H2Padding

(Apache Httpd 2.4.39以降)

ペイロードフレーム長さを観測されにくくするため、パディングバイトを追加します。

0から8までの数値を設定できます。

0がデフォルトで、この場合パディングバイトは付加されません。 後方互換性が最大となります。

1以上に設定すると、ペイロードフレーム長さから内容を推測される可能性が減りますが、その分無駄な通信が発生します。

8なら、0~256(2の8乗)の、いずれかの長さが、ペイロードフレームを送信する毎に、乱数で決定され、その長さのパディングバイトが付加されます。

つまり、8が設定された場合、期待値としては、約128バイトのパディングバイトが付加されます。

4が設定された場合、0~16(2の4乗)のいずれかの長さのパディングバイトが付加されるので、期待値としては、約8バイトのパディングバイトが付加されます。

H2SerializeHeaders

HTTP/2のバイナリ形式のリクエストヘッダを、HTTP/1.1フォーマットに変換します。

パフォーマンスの悪化につながりますが、カスタムモジュールの後方互換性の確保します。

モジュールの互換性の問題が起きていなければ、デフォルトのまま、offで良いです。

H2SerializeHeaders off

H2Direct

ダイレクト方式によるh2c通信を許可するか指定します。

デフォルトは、h2cの場合、on、 h2の場合、offとなります。

詳しくは、動作確認をご覧ください。

H2Direct on

H2Upgrade

Upgradeヘッダを利用したアップグレードを許可するか指定します。

デフォルトは、h2cの場合、on、 h2の場合、offとなります。

H2Upgrade off
NEXT >> http/2のチューニング

©Copyrights 2015-2023, non-standard programmer

このサイトは、あくまでも私の個人的体験を、綴ったものです。 軽く参考程度にご利用ください。