WEBを高速化するには様々な方法があり、単純に高スペックのサーバーを並べただけではどうしても解決出来ない問題も存在します。今回はハードウェアレイヤーではなくその少し上のトランスポートレイヤーのチューニングの一つ TCP FAST OPENにつてご紹介します。
TCP FAST OPENとは?
TCP FAST OPENとは「トランスポートレイヤーでTCPの通信方式を最適化する」手法です。※略してTFOと呼ばれる事もあります。TCP FAST OPENがRFC化したのは2014年12月(RFC7413)となり、実は少し前のお話となります。Linuxのカーネルでは3.6から実装されておりその後のバージョンでは標準で有効化されています。
3 Way Handshake
TCP通信は通信相手との信頼性を保証するため、以下のような動作を必ず行います。
これらはTCP通信を開始する場合常に行われる決まり事です。そのためHTTPでもHTTPSでもFTPでも通信するときはこのようなネゴシエーションを行ってからコンテンツを取得する動作に入ります。
このように、毎回3回リクエストを送信し合う通信の最適化を行えるのが、TCP FAST OPENです。
そもそも何故3回も通信するのか?
TCPは通信の信頼性や相手のIPアドレスの偽装がないか等の保証を行うために3回も通信をしています。そのため、必ず相手側に通信する事を通知し、相手側からOKがもらえた後にデータの送信を行う必要があります。
TCP FAST OPENの動作
TCP FAST OPENは先ほどの3回のハンドシェイク中にデータ送信を許可します。これにより、コネクションがオープンでない場合でも遅延なしにリクエストを送信することができ、高速化が可能となります。
しかし、その場合通信の保証をするという目的とそれを待たずにデータ送信を許可してしまうという矛盾が生じます。そのため、TCP FAST OPENは以下のようにCookieを使った手法で通信の保証を行っています。
TCP FAST OPENは初めて通信を行う場合、通常の3 Way Handshakeを行います。その際クライアントからSYN に Fast Open Cookieを付けて通信する所から始まります。初回通信の流れは以下の通り。
初回の通信
- クライアントは、SYNに Fast Open Cookie Requestをつけて送信する。
- サーバーは、 SYN+ACKを返す際にTCPオプションの34番でTFOクッキーを返す。
- クライアントは、ACKを返し通常の接続確立を終える。※この時、TFOクッキーをキャッシュします。
ここでサーバが生成するTFO-Cookieは、クライアントのIPアドレスやサーバーシークレットなどからAES-128で作ったものとなります。 クライアントはこのTFO-Cookieを、次回以降の接続で使用するためにキャッシュします。
※クライアントのIPが変わるとCookieが無効になります。
初回以降の通信
初回以降の通信では、SYNに初回の通信でキャッシュしたTFOクッキーとHTTP GETのリクエストデータが付くことが大きな違いです。TFOクッキーから正しいIPであればクライアントからACKがくる前にGETデータを渡すことが出来ます。このように通信確立時の1RTTを節約することが出来るというのがTCP Fast Openのメリットです。
初回以降の通信の流れは以下の通り
- クライアントは、SYNパケットにキャッシュしたTFOクッキーとリクエストデータを含めて送信する。
- サー バーは、クライアントから送られてきたTFOクッキーを受け取り、再度SYNからTFOクッキーを生成したものを、クライアントから受け取ったTFOクッキーと比較し正しいかどうか判断。正しければ、サーバーはリクエストデータをアプリケーションに渡し、クライアントにはSYN-ACKを返却する。このとき、受け渡すデータがあればSYN-ACKと同時にレスポンスする事が出来ます。
- クライアントはACKを送信する。
クライアントとサーバー双方の対応が必須
TCP FAST OPENは通信の仕組み上Cookieを送信しあい認証を行う為、サーバー側とクライアント双方での対応が必須となります。CDNの場合、初回アクセスに限ってはオリジンサーバーと通信後クライアントにコンテンツを返却するため、通常のクライアントとサーバー間の通信と比べ最大4分の1のRTTでコンテンツを配信することが出来ると言えます。
未対応の場合はどうなるのか
最初のSYNを受け取ったサーバーがTCP FAST OPENに未対応だった場合や、クライアントのTFO-Cookieが無効と判断された場合は、オプションを無視して通常の3WHが実行されます。
TCP FAST OPENの検証
それでは、実際どの程度の高速化が出来るのか以下の環境で検証してみたいとおもいます。
サーバー側(CDN)
・Linuxカーネル3.6以降 (Centos6にカーネルを独自ビルドしたものを利用します。)
・Nginx(Latest)
NginxでTFOを有効にするにはコンパイル時に、以下のオプションを指定して下さい。
–with-cc-opt=”-DTCP_FASTOPEN=23″
また、Listenしている部分に以下のパラーメーターを記述する必要があります。
fastopen=256 例: listen 80 fastopen=256;
クライアント側
httping
TFO無効
httping -g https://test-domain.redbox.ne.jp -c 10
某国内ロケーションから
round-trip min/avg/max = 53.7/74.9/139.1 ms
某海外ロケーションから
round-trip min/avg/max = 60.2/188.0/1123.6 ms
TFO有効
httping -g https://test-domain.redbox.ne.jp -c 10 -F
※-FオプションでTFPを有効にします。
某国内ロケーションから
round-trip min/avg/max = 25.7/45.8/103.4 ms
某海外ロケーションから
round-trip min/avg/max = 51.1/57.8/96.3 ms
このようにTCP FAST OPENを利用した場合、レイテンシが高いロケーションでは特に効力を発揮することが分かったと思います。また、Tcpダンプでパケットを取得すると、クライアントは SYN パケットに TFO クッキーとデータを合わせて送信していることも確認できます。
他にも、TFOで通信していると以下のようにNetstatでカウンターが上がっていきます。
netstat -s | grep TCPFastOpen
TCPFastOpenActive: 25
TCPFastOpenPassive: 10
まとめ
今回はTCP通信を最適化するTCP FAST OPENについてご紹介しました。WEB高速化といってもレイヤーによって様々な手法があることがお分かりいただけたと思います。CDNは通常のWEBサーバー直接の通信と異なり、初回アクセスはオリジンからコンテンツを取得する関係上、通常のアクセスより遅くなることがありますが弊社ではロケーションにあわせた最適なチューニングを行っています。