KeepAlive とは
一般に、ある 2 つの機器間の通信接続において、相手が活きているかを確認し、その接続を維持する仕組みを KeepAlive と呼びます。
KeepAlive は TCP や http, IPsec, BGP 等、様々なレイヤー・プロトコルで実装されていますが、それぞれ仕組みや狙いが少し異なります。
本記事では代表的な例として TCP KeepAlive と http KeepAlive の仕組みや違いについて紹介します。
TCP KeepAlive の仕組みとメリット
TCP KeepAlive とは、TCP コネクションを確立したホスト間において、通信開始からしばらくして相手からの通信が途絶えた際に、相手が活きているかを確認する仕組みです。
RFC 1122 で定められているものの、必ずしも使える必要は無いとされています。つまり実装していない機器であっても TCP に準拠していると言える訳です。
TCP KeepAlive のメリットは、ネットワーク機器が原因による通信障害を確認し、不要なコネクションを開放できることです。ネットワーク機器が原因による通信障害には、単純な機器故障に加え、ファイアウォールのステートフルインスペクションのセッションタイムアウトや NAT のセッションタイムアウトによる通信不可も含まれます。
パケットキャプチャ
Windows 同士が送信する TCP KeepAlive を Wireshark でパケットキャプチャすると以下のように見えます。
[ TCP Keep-Alive ] : TCP KeepAlive 送信側
1 Byte の "00" を送信しています。RFC 1122 には以下の記述があります。
An implementation SHOULD send a keep-alive segment with no data; however, it MAY be configurable to send a keep-alive segment containing one garbage octet, for compatibility with erroneous TCP implementations.
RFC 1122 では『Data は無しにすべき』と言いつつ、『TCP KeepAlive を理解しない (実装していない) 相手もいるかもしれないので配慮して 1 Byte の無駄な通信をしてもよい』と言っています。
[ TCP Keep-Alive ACK ] : TCP KeepAlive 応答側
KeepAlive 送信に対する ACK を返しています。(何故か SACK?)
Windows の設定パラメータ
Windows は以下 2 つのレジストリを追加することにより設定が可能です。
① KeepAliveTime レジストリ
『TCP コネクション開始から KeepAlive の送信を開始するまでの時間』を指定します。単位は msec 、デフォルトでは 7,200,000 msec = 2 時間です。つまり、デフォルトでは TCP コネクション開始から 2 時間以降にならないと KeepAlive メッセージは送信されません。
② KeepAliveInterval レジストリ
『KeepAlive 送信開始後、何ミリ秒間隔で次の KeepAlive を送信するか』を指定します。単位は msec、デフォルトでは 1000 msec = 1秒です。
Windows の設定方法
Windows キー + R ⇒ "regedit" と入力し Enter を押下 ⇒ 起動したレジストリエディターの以下のパスを辿ります。
"Parameters" を右クリック ⇒ "新規" ⇒ "DWORD (32ビット) 値(D)"をクリック
有効な範囲: 0-0xFFFFFFFF (msec)
有効な範囲: 0-0xFFFFFFFF (msec)
Linux の設定パラメータ
Linux はカーネルパラメータとして以下の3つが定義されています。
[root@localhost ~]# sysctl -a | grep keepalive
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
① net.ipv4.tcp_keepalive_time
『TCP コネクション開始から KeepAlive の送信を開始するまでの時間』を指定します。単位は sec 、デフォルトでは 7,200 sec = 2時間です。(Windows と同じです)
② net.ipv4.tcp_keepalive_intvl
『KeepAlive 送信開始後、何ミリ秒間隔で次の KeepAlive を送信するか』を指定します。単位は sec、デフォルトでは 75 秒です。
③ net.ipv4.tcp_keepalive_probes
『KeepAlive を送信し、何回応答が無かったら TCP コネクションを切断するか』を指定します。単位は回数、デフォルトは 9 回です。つまり 75秒× 9 回送信して応答が無かったらコネクションを切断、リリースします。
http KeepAlive の仕組みとメリット
http KeepAlive は、1つの TCP コネクションの中に複数の HTTP リクエストを実行できる機能です。これにより通信の効率化が図れるというメリットがあります。
これによる速度向上などたいしたことないように感じるかもしれませんが、今や 1 つのページに数十、数百の GET メソッドが必要なサイトも多くあります。
そして実は一方的に送るのではなく、相手からの応答を待つ Handshake 系通信 (TCP コネクションや SSL/TLS コネクション) は現状ボトルネックであることが Google の調査でも明らかになっています。(この流れが TLS v1.3 や HTTP/3 に繋がっています)
http KeepAlive は HTTP 1.0 ではオプション扱いですが、HTTP 1.1 からはデフォルトで有効になっています。
TCP KeepAlive には ACK による response (応答) がありますが http Keep-Alive にはそれがありません。コネクションを閉じるのではなく維持する、という意味合いになります。
パケットキャプチャ
以下に http KeepAlive のサンプルパケットキャプチャを示します。1つの TCP コネクションにおいて、2つの GET メソッド (HTTP リクエスト) が投げられています。また、GET メソッドのある HTTP ヘッダに "Connection: keep-alive" が付加されていることも分かります。
Apache での http KeepAlive の設定
Linux の Apache の設定ファイル (/etc/httpd/conf/httpd.conf 等) に、以下のパラメータを記載することで設定することができます。
① KeepAlive { On | Off }
例:KeepAlive を有効にする
KeepAlive On
② MaxKeepAliveRequests [num]
例:1 つの TCP コネクションにおいて最大 10 リクエストまで許可する
MaxKeepAliveRequests 10
③ KeepAliveTimeout [sec]
例:5 秒待って次のリクエストが来なければ TCP コネクションを閉じる
KeepAliveTimeout 5
KeepAlive のデメリット
KeepAlive は通信効率性を追求することのトレードオフとして、サーバ側は TCP コネクションを確立し続けることに負荷が掛かることがデメリットです。
性能を追求する nginx では「イベント駆動」と呼ばれる方式でこのデメリットを克服しています。また、Apache でも同様の方式を実装し始めています。こちらの詳細については以下を併せて参照下さい。
コメント