前日は HTTP2におけるProxyに関する議論 でした。
(あらすじ・前略)
もっこすにはHTTPがわからぬ。もっこすは、ただのゲーマーである。ヴァナディールで市場価格操作に命を懸け、艦娘と遊んで暮らしてきた。けれどもトランスポート層のプロトコルについては、人一倍に敏感であった。
QUIC
HTTP2とは直接関係ないので、念のため概要を説明してから進みます。HTTP2勉強会 #http2studyシリーズに参加されている方だと、もうご存知の方が多そうな気はしますが、とりあえず。QUICとは、Googleが開発しChromiumに実装中のトランスポート層、すなわちTCPと同じ層のプロトコルです。Internet上で運用される独自実装トランスポートの常として、UDPで包んだ中に独自実装が入っています。
QUICの主目的は、1にも2にも接続開始時の遅延削減です。Design Documentをはじめ各所には、QUICによるメリットがいくつも箇条書きされていますが、最初の遅延削減だけは飛びぬけてプライオリティが高いです。せっかくの新プロトコルなので、改良できそうな点はたくさんありますが、Webを扱うGoogleとしてのプライオリティは明確に「ページを早く表示する」ことに置かれているのです。IETFでの発表資料(PDF注意)でも、太字になっていますよね?
最低限の概要説明はここまで。以後、QUICで使われている技術要素から、面白そうなものを紹介していきます。
マルチストリーミング
QUICでは、ひとつの接続(Connection)の上に、複数の論理的接続(Stream)が走ります。- Streamに優先度をつけたり
- Stream毎に違う挙動にしたり
- 再送制御をStream毎に独立して行ったり
このマルチストリーミングは、SCTPというプロトコルでかなり前から用いられています。SCTPについての説明は、古いですがIBM Developer worksのものをどうぞ。"2000年10月にRFCになった比較的新しいプロトコルです"なんて書いてありますね…。
既にあるならば、それを使えば良いではないですか! 実際WebRTCのデータ転送では、DTLS(UDP+セキュリティ)の上にSCTPが走っています。このレイヤーを弄っているギークなら、QUICを見て最初に思う事は「なんでDTLS+SCTPじゃダメなの?」であって、Design DocumentにもQUIC FAQ for Geeksにも理由の説明があります。本件の説明はこの後で少しずつ。
0-RTT connection
古き良きTCPで接続すると3-way ハンドシェイクによる接続が始まり、上にセキュリティレイヤーがあればそのレイヤーでも情報が行ったり来たりして、ようやく通信が始まります。これはたまらん。特に、RTTの長い場合に、ページが表示され始めるまでの時間がやたら長くなってしまいます。TCPには、既にTCP Fast Openという技があります。乱暴に説明するならば、一番最初のパケットにリクエスト内容も載せてしまえるもの。Linuxカーネルには年単位で昔に入っていますが、クライアント側での普及率はまだかなり低いのではないかと思われます。BSDソケットAPIのconnect()にはデータを載せられないので、TCPなのにconnect()ではなくてsendto()で接続しに行くんですけど、どれくらいの方が使用経験ありますかね?
(左が普通のTCP、右がTFOが上手くいったときの図)
TFOのI-D見ると、しっかりGoogleの名前が入っています。Googleの資料に "Deploy in today's internet"と書いてある部分は、TCPにコントリビュートしても、浸透に何年かかるんだよ!という怒りが込められているのかもしれません。もちろん、QUICでは同様の技が実装されます。
QUICで遅延関係でもう一つ進んだところは、トランスポート層と、その上のセキュリティ関係の層(のハンドシェイク)をまとめて済ませようとしているところです。仮想化・レイヤー構造ってものは、柔軟に差し替えられるように存在するものであって、TLSを他に差し替える必要がないのであれば必要ない…という判断は理解できます。これが、DTLSでハンドシェイクして、SCTPでハンドシェイクして、と何度も往復しなければならない DTLS+SCTPとの違いになります。(他にTLS層でいくつかメリットがあるけども割愛)
WebRTCの選択が悪いわけではありません。あれはコネクション張りっぱなしで色々するものなので、Googleのシナリオとは接続遅延の重要性が全く違います。そこの性能向上が要らないわけではないので、いずれQUICが成熟したら、置き換えの可能性はあるでしょうが…
ペーシング
ペーシングは、パケット送信間隔を均してバースト転送を避けることで、経路上のバッファ溢れによるパケットロスを減らす仕組みです。これを他人に説明するときには、いつも産総研のPSPacerのページに丸投げしています。良い説明です。新しい技術ではありませんが、QUICの送信制御に入るようです。FEC (エラー訂正)
QUICには、パケットレベルのエラー訂正の仕組みが実装されています。仕組みは単純で、パケットN個のグループあたり1個のエラー訂正パケット(他のパケットのXOR)を追加で送ることにより、そのグループ内でパケットロスが1個ならば訂正し、再送を抑えることが出来る、というもの。(RAID5を思い浮かべましょう)追加で余計な情報を送るので、再送遅延の節約と、余計な帯域消費とのトレードオフです。
ハンドオーバー
QUICはコネクションに対して64bitのユニークな値を付与し、これをIDとします。既存のInternetトランスポート層では基本的に、IDとなるのは {アドレス, ポート番号} でした。もちろん、アプリケーションレイヤーまで行けばちゃんとユーザーIDなどがありますが…。IDがアドレスから切り離されることにより、仮にIPアドレスやポート番号が変化したとしても、それをトランスポート層で吸収して隠蔽することができます。接続が切れたからとハンドシェイクをやり直す必要がなくなり、すなわち次にWebページ等を表示したときの遅延が解消されます。モバイル環境で端末が大きく移動したとき、回線を3GからWiFiアクセスポイントに繋ぎかえたときに利点が得られるであろうことは、想像が付きますね。既存技術では、機能の観点からはmobile IPに相当するでしょうか?
QUICの場合、このID仕様が生きる場面はもう一つあり、それはNAT(NAPT)のポートマッピング変更です。UDPはコネクションの概念がないので、既存のmiddleboxはタイムアウトとかLRUとかを用いて、NAPTのマッピングを消したり変えたりします。同じように通信しているつもりが、いつのまにかさっきとユーザー側のポート番号が違う、という恐ろしいことが起こります。そこでこのID仕様が役に立つ…というより無いと困ってしまうわけです。
ついでにNAPTの話をもう少し
NAPT問題は、QUICの実用に向けて、一番難しい課題かもしれません。NAPTエントリが消滅したら、装置の内側から一発飛ばさないと穴が開きません。サーバーからの通信は、タイミングが悪いと落ちてしまいます。定期的に穴あけをしたいですが、keepaliveであまり帯域を食うのも微妙だし、モバイル端末ならバッテリーの問題もあります。つまらない話ですが、TCPへのフォールバックは必ず用意する必要がある、のかもしれません。
keepaliveの間隔はGoogle側で話題になっているし、NAPTのタイムアウト時間設定はISP側で悩ましい問題になりそうです。IPv6ならば、NAPTかまさず出てこられるかもしれないので、ここでv6への機運がなぜか高まる、というシナリオに進んだら面白いと思います。(あまりなさそうと思いつつ書いている)
近況
QUICはその実験的性格から、公開まで時間がかかるのではないかと心配していましたが、意外と早い時期に手の届くところに来るかもしれません。つい最近のQUIC Prototype Protocol Discussion groupの投稿によると…we're hoping to engage other developers and get real server implementations (apache, nginx etc.) in 2015.nginxやapacheに載ってしまえば、あとは設定を変えれば動いてしまうわけで、2015年は良い意味でHTTP激動の年になってくれるかもしれません。HTTP/2のみならず、です。楽しみにしましょう!
〆
この記事では、QUICで実装されている高速化技術を、できるだけ既存の対応する技術と関連させつつ紹介しました。セキュリティ関係は、若干地味な上に背景を説明するのに分量が必要なので、かなり割愛しています。興味のある方は、Design Documentに説明があったはずなので、そちらをどうぞ。…ああ、思いつき3秒で書いたあらすじの伏線が投げっぱなしで回収されていない。どうしよう。困った。
万歳!Google様万歳!
---
この投稿はHTTP2 Advent Calendar 2014の18日目の記事でした。
後日、ここに翌日へのリンクが入ります。
0 件のコメント:
コメントを投稿