はじめまして。プロダクト開発チームの小野寺 (ryoqun)です。
今回は最近少しずつ浸透し始めてきた「TCP Fast Open(以下、Fast Open)」という最新技術についてTCP/IPのおさらいを踏まえながら紹介したいと思います。ちなみに、この技術はTCPを高速化するもので、Google、Facebook、Appleなどでも本番投入され初めているものの、まだ国内では浸透していなくだいぶ先取りな紹介となります。
Fast Openという技術は比較的枯れたTCPに対してプロトコルレベルで変更を加える比較的インパクトが大きいと勝手に思っている技術です。 最近は低レイヤーの技術はアプリケーション・サービス開発エンジニアだとあまり意識しないとは思いますが、基礎は大事なので 最新動向を掴むと共に、TCP/IPの良い復習ということで少しの間ですがお付き合い下さい。
Fast Openとは?
一言でいうとTCPのレイテンシーを改善する新しい拡張技術です。具体的には接続確立時(= Open)のレイテンシーを軽減(= Fast)します(よってFast Openという名前の由来となっています)。正確には、TCPのThree-way handshakeを省略することで1 RTT分のレイテンシーを削減できます。
Three-way handshakeを明示的に省略する必要性から、クライアント側とサーバー側の両方がFast Openに対応して初めて有効になります。
注意点としては、僅かに接続確立時の信頼性が犠牲となることです。これについては後述します。また、各ホストへの初回接続時には使えません。理由は、セキュリティのため認証情報(Cookie)が必要になるためです。これはTCPのSYN flooding攻撃に似た危険性を軽減する対策余地をプロトコル上に残すためです。
Three-way handshakeとFast Open
本来ならばTCPだとThree-way handshakeが必要になります。つまりは接続確立時に実際の通信ができるまでに、まずクライアント側からSYNフラグが立ったペイロードが無い小さいパケットを送り、サーバー側からSYN+ACKフラグが立ったペイロードが無い小さいパケットを受け取らなければなりません。これがまさしく1 RTT分のレイテンシーに相当するわけです。
他方でFast Openが有効な場合、接続確立時にいきなりSYNフラグを立てた上で、ペイロードを乗せることができます。例えば、HTTPリクエストがTCPのMSS以下の場合は、0 RTTでnginxなどのHTTPサーバーはリクエストの内容をアプリケーションプロセスに渡すことが実現可能です。ただ、現在だとHTTPというよりかはHTTPS(=TLS)が主流です。その場合はTLS handshakeを即座に開始できるというわけです。なお、Fast OpenとTLS 1.3を組み合わせるとTLSを含めて0-RTTを実現できるようになるようです。
デモ
百聞は一見にしかずということで、まずは実際の動きを見てみましょう。
Fast Openが有効になっているサイトから、Fast Openが有効になっているブラウザでファイルをChromiumでダウンロードしてみました。その時のChromiumのDeveloper toolsのNetworkのtimingとWiresharkで状態を確認してみました。ちなみにテストに使ったサービスはWikimediaですが、Fast Openが有効なサービスにはGoogleなどもありますが、日本国内からのアクセス時にレイテンシーが発生しFast Openの効果がわかりやすくなるようにWikimediaを選んでいます。
ChromiumのDeveloper tools
Fast Openが無効と有効になっている時の違いを比べてみました。
無効時:
有効時:
赤の矢印(↑)のところに着目するとわかるように、Initial connection(= TCPのThree-way handshakeのこと)がFast Open有効時は必要なくなっていて、SSLのhandshakeが前倒しになって開始されているのがよくわかります。ただ、SSLのhandshakeにかかった時間や実際のデータの転送にかかった時間はそれほど変わっていません。結果としては、Initial connection分の時間(レイテンシー)だけが綺麗に全体のレスポンス時間から減っています。
Wireshark
Fast Openが無効と有効になっている時の違いを比べてみました。
無効時:
有効時:
赤枠(□)のところに着目するとわかるように、Fast Open無効時は、TCPのThree-way handshakeをちゃんとやっています。しかしFast Open有効時は、Three-way handshakeをスキップしていきなりペイロード(Client Hello; TLS handshakeの最初のパケット)があるパケットを送っているのがわかります。結果、パケットのLengthが大きくなっています。なお、このスクリーンショットからはわからないのですが、この最初のパケットにはSYNフラッグがきちんと立っています。その後のやり取りの流れは無効時と変わりありません。
長所と短所
- ○ 接続確立時のRTTが減る!!!!(これは前述の通りですね)
- △ 接続確立後のデータ通信のレイテンシーは向上しない(Fast Openは接続確立時だけの話です)
- ✕ アプリケーション層での冪等性が必要(これについては後述します)
短所: アプリケーション層での冪等性が必要
これが、この記事の冒頭で書いたFast Openを有効にすることによって犠牲にされた信頼性となります。しかしながら、この懸念を考慮する必要はインターネットから到達可能なWebサービスにおいてはほとんどありません。より正確にいうと、そのような前提の場合はブラウザの多重Submit問題と同じ問題であり、ネットワーク起因やユーザー操作起因の違いはあれど、Fast Open抜きにしても必ず考慮する必要があるからです。しかし、TLSを使っていなかったり、あるいは、イントラネット内で完結するWebサービス、またはTCP本来の高信頼性を要求する通信にてFast Openを有効にする場合には懸念となります。
そのFast Openを有効にした際の信頼性の問題というのは、1つのTCP上のアプリケーションリクエストがIP通信網の品質の問題により、2つになりえるという理論的な問題となります。そのためアプリケーション層において、リクエストが2つになっても問題無いという冪等性が必要になります。
その問題の原因を説明する前にまずは、前提となる背景を説明します。TCPの役割というのは、信頼性が担保されないIP通信上に、信頼できる双方向通信路を実現するためのプロトコルです。Three-way handshakeはその信頼性の担保のために接続確立時に必要となります。当時のTCPの設計に問題があったわけでもなく、現時点に至るまでの技術的発展があったわけでもなく、昔も今も、レイテンシーと信頼性のトレードオフの結果、本来のTCPは信頼性を重視するためにはThree-way handshakeを必要としています。反面、IP通信は、設計思想として、耐障害性、冗長性を重視し、ごく稀なパケットロスやパケット重複は許容しています。
というわけで、Fast Openを有効にした上で、Three-way handshakeが省かれ、パケット重複が万が一発生した場合、サーバーにとってはあたかもTCP接続確立が2つ来たかのように見えるので、2回リクエスト処理をしてしまうということになるわけです。
普及状況
繰り返しになりますが、Fast Openはクライアント側とサーバー側がどちらも対応して初めて使えるようになります。具体的にいうと、TCP/IPスタックは多くの場合、OSが実装しているので、OSがFast Openを実装し、それが有効になっている事と、ミドルウェアやアプリケーションが対応している事が必要になります。
クライアント側とサーバー側に分けて、2017年9月時点での普及状況について説明します。
サーバー
Google, Wikipedia, CloudFront, Facebookで有効になっているようです。Fast Openはどちらかというと一般的なWebサービスでは効果が出にくく、CDNや広告配信等の1ショットのHTTPリクエストのトラフィックが大量に発生する場合に効果的です。日本サイトは筆者が簡単に確認する範囲では見つけられませんでした。
クライアント
Webブラウザはそれぞれ対応が始まっています。筆者はUbuntu 16.04/LTSのChromiumで動作確認をしています。 OS的にも、iOS、Android、Windowsでそれぞれ動きがあるようです。
ツール/ミドルウェア
ちらほらとサポートが始まっています。網羅的に調べたわけではありませんが、netty、Ruby、curlなどで対応情報を見つけることができます。
他の技術との関連
最後に、Fast Openがそれぞれ他の技術とどのような関連を持つのかを見てみて、Fast Openの理解を多角的に深めていきたいと思います。
NAT
NATの実装によっては、Fast Openとの相性が良くない場合があります。これは当然で、NATはその原理上TCP接続の状態遷移をトラッキングしなければならないのですが、NATの実装が厳しすぎると、Fast OpenによってThree-way handshakeが省かれれば十分に正しくトラッキングできなくなる場合はあります。
HTTP keep-alive
HTTP通信におけるTCPの接続確立時のレイテンシーを軽減するという目的の上では、Fast OpenもHTTP keep-aliveも同じ立ち位置です。HTTP keep-aliveによってだいぶレイテンシーは改善されます。なので通常のブラウジングでは、keep-aliveに比べてFast Openというのはそれほど如実に効果があるわけではありません。ただ、Fast Openの策定背景としては、HTTP keep-aliveはモバイル回線網にてあまり機能していないという指摘もあります。
スマートフォン向けのHTTP APIのエンドポイント
アプリがkeep-aliveしていないならば効果はあります。ただし、まずはkeep-aliveを対応したほうがいいのは言うまでもありません。
ラストワンマイル回線網(FTTHと4G)
宅地のラストワンマイル回線網というと今で言えば日本国内で言えば、FTTHが圧倒的なシェアになっています。FTTHで通信ホストが国内の場合はそもそものレイテンシーは数msなのでFast Openの効果はほとんどありません。ADSLならば多少は効果はあります。しかし、ラストワンマイルが何にしろ、海外ホストへのアクセスの場合には効果が望めます。
モバイルのラストワンマイル回線網というと今で言えば4G回線が全盛となっています。こちらの場合は国内ホスト、海外ホストに限らず一定のレイテンシー向上が望めます。
Supercookie
Fast Openの際に使われるCookieの転用例としては、Supercookieが挙げられます。セキュリティ上、DOS攻撃対策としてCookieが必要なわけですが、別のセキュリティ観点では、匿名性が犠牲となっています。特にE-tag、HSTS同様、passiveでドメインをまたいだ(=クロスドメイン)トラッキングが実現できてしまいます。今回新たにFast Openがトラッキング手段として加わったわけですが、他の既存の代替手段も存在するのも含め、残念ながらトラッキングを現在において完全に抑制することは非常に困難となっています。
HTTP/2
HTTP/2になってもTCPベースなので引き続きFast Openは意味があります。しかしQUICに対してはこちらはUDPベースなので関係なくなります。
参考情報
- 仕様(比較的手頃な文量でまとまっていて読みやすい)
- WWDC 15での言及(冪等性についてわかりやすい図があります)
- Chromiumの開発者の考察
- Microsoftの0-RTT TLSと絡めながらの言及
まとめ
- レイテンシーが速くなります。
- 半世紀近く変わらなかったTCP(のThree-way handshake)が地味に変わるかもしれません。