HTTPを効率よく使用するためにTCPのチューニングはかかせません。
Best Current Practiceカテゴリとして「TCP Tuning for HTTP (draft 00)」というInternet-Draftが提出されているので、ざっと目を通した。(割と適当)
大きく分けて下記の5つについて書かれており、特筆のない限りHTTP/1.1でもHTTP/2有効なプラクティスです。
(1はイントロダクション
2 Socket planning
2.1 Number of open files
殆どのOSでソケットを開ける数は、オープンできるファイル数と等しいです。
その上限がボトルネックになっていないことを確認する。
Linuxでは上限を上げることが出来ます
fs.file-max = <number of files>
2.2. Number of concurrent network messages
カーネルが処理できる以上のパケットを受信した際にキューに積むことが出来るパケットの数を上げる
Linuxでは以下のとおり指定できる
net.core.netdev_max_backlog = <number of packets>
2.3. Number of incoming TCP SYNs allowed to backlog
新しいコネクション要求をキューに積む事ができる数。
Linuxでは以下のとおり指定できる
net.core.somaxconn = <number>
2.4. Use the whole port range for local ports
TCPスタックが最大限ソケットを全て使用できるように、ローカルポートの数を広げる。
net.ipv4.ip_local_port_range = 1024 65535
2.5. Lower the TCP FIN timeout
コネクションがFIN-WAIT-2状態の時間を少なくすることで、より早く再利用できるようになり同時接続数を増やすことが出来ます。
net.ipv4.tcp_fin_timeout = <number of seconds>
2.6. Re-use sockets in TIME_WAIT state
ネットワークスタックの観点から安全である場合は特に、新しい接続のためのTIME_WAIT状態にあるソケットの再利用を可能にします。
net.ipv4.tcp_tw_reuse = 1
2.7. Give the the TCP stack enough memory
高速に大量のTCPコネクションを処理するシステムはTCPスタックバッファに沢山のメモリを必要とします。
TCPスタックにデフォルトのバッファサイズや、どれくらい動的に拡大・縮小していいか指定できます。
net.ipv4.tcp_wmem = <minimum size> <default size> <max size in bytes> net.ipv4.tcp_rmem = <minimum size> <default size> <max size in bytes>
2.8. Set maximum allowed TCP window sizes
許可された最大ウィンドウサイズを増やしたほうが良いかもしれない。
net.core.rmem_max = <number of bytes> net.core.wmem_max = <number of bytes>
3. TCP handshake
3.1. TCP Fast Open
TCP Fast OpenはTCPハンドシェイク中にデータ送信を許可します。それによって、コネクションがオープンでない場合でも遅延なしにリクエストを送信することが出来ます。
TFOはクライアントとサーバ両方のサポートが必要です。SYNで送られるデータが冪等である必要が有るため、アプリケーション側もその事に対する認識が必要です。
それゆえ、TFOは冪等なときのみ使用でき、GETやHEADと言ったHTTPメソッドや、TLSなどを使用している時に使用することが出来ます。
TFOのサポートが原因でそれが与える重要なパフォーマンス上の利点に、モバイル環境などがあります。
3.2. Initial Congestion Window
RFC6928では初期服装ウィンドウを10としていますし、サーバサイドでは広くデプロイされています。
パケットペーシングとの組み合わせで、より大きな初期ウィンドウを用いた実験がありました。IW10があっても、大量のサーバに非常にフェアに実行されることが報告されています。
4. TCP transfers
4.1. Packet Pacing
4.2. Explicit Congestion Control
iOS と OSXで使用できる
https://developer.apple.com/videos/wwdc/2015/?id=719
4.3. Nagle's Algorithm
Nagle'sアルゴリズムは(RFC0896)は、送信するパケットを少しだけとどめて次に送信するパケットとマージする仕組みです。遅延を犠牲にスループットを最適化します。
特にHTTP/2では、片方向に受信が行われている間は高速にパケットを返すことが要求されます。小さな遅延でも重大なパフォーマンス損失を引き起こします。
HTTP/1.1でも、一つの write()システムコールでリクエスト全てを送信するときに特に影響を受けます。
POSIXシステムでは下記のように変更できます。
int one = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
5. Re-using connections
6. Closing connections
6.1. Half-close
クライアントやサーバはリクエストやレスポンスの後にハーフクローズに出来ます。HTTP/2では停止中のストリームが無ければ。
ハーフクローズは稀にサーバが綺麗にコネクションを切断する唯一の方法となります。それは、サーバはさらなるリクエストの受け入れをせず、クライアントに送信中のレスポンスの受信を許可する。
6.2. Abort
クライアントはリクエストボディを送信し終わった後にHTTP/1.1の接続をabortしません。
RSTを防ぐためにフルクローズにはエラーレスポンスが期待されます。
6.3. Close Idle Connections
後続の接続のために、接続を再利用できるように維持することは、HTTPクライアントのパフォーマンスにとって重要です。
既存のコネクションの価値はすぐに低下し、数分後にはブラウザによって再利用される可能性はわずかです。
6.4. Tail Loss Probes
http://tools.ietf.org/html/draft-dukkipati-tcpm-tcp-loss-probe-01