[追記] QUIC, HTTP/3 関連記事
まるっと解説記事を書き直しました
asnokaze.hatenablog.com
その他もどうぞ
- QUIC, HTTP/3の標準化状況を確認したい (2019年11月版) - ASnoKaze blog
- HTTP/3と新しいプライオリティ制御方式について - ASnoKaze blog
- QUICのコネクションマイグレーションについて - ASnoKaze blog
- QUICのAckとロスリカバリについて - ASnoKaze blog
- QUICの暗号化と鍵の導出について - ASnoKaze blog
- HTTP/3のヘッダ圧縮仕様QPACKについて - ASnoKaze blog
- WiresharkでのQUICの復号(decrypt) - ASnoKaze blog
- QUIC,HTTP/3 の draft-17に関するメモ - ASnoKaze blog
- QUICの話 (QUICプロトコルの簡単なまとめ) - ASnoKaze blog
2019/09/15 追記
古い記述に加筆修正を入れました
目次
前回書いたとおり、現在IETFでQUICの標準化がされている
(QUICのトランスポートレイヤについては、下記記事参照)
asnokaze.hatenablog.com
今回はちょうどホットなHTTP/3の名称と、概略について雑に書く
HTTP/3で何が変わるか
(補足: この章は新しく追記されました。)
現在の仕様は「Hypertext Transfer Protocol Version 3 (HTTP/3)」こちら。
さてHTTP/3というと、なにか新しそうなHTTPのような気がしますが、まず基本的なHTTPのセマンティクスに変更はありません。GETやPOSTといったHTTPリクエストがあって、ステータスコードを持つレスポンスが返されます。つまり、HTTPとはそのメッセージの意味であり、HTTP/1.1、HTTP/2、HTTP/3でその伝え方が異なっているという解釈をするとわかりやすいです。
余談ですが、HTTP/1.1の仕様である HTTP/1.1 (RFC 7230 〜 7235) から、HTTP/1.1固有のもとのHTTPのセマンティクスに関する定義を分離しする作業が進められています(参考)。
さて、HTTP/3になり、トランスポートとしてQUICを使用するようになりました。これにより、Head of Line Blockinが解消しています。
HTTP/2では、パケットロスが発生した場合はOSレイヤでそのパケットが再送されてくるのを待ってからアプリケーションにデータを渡していました。つまり、ロスしたパケットよりあとのデータが届いていたとしても活用することはできませんした。
HTTP/3ではパケットがロスしていても、後続の届いたデータが処理可能であれば、処理を続けます。これが、Head of Line Blockinの解消です。
また、QUICを使用することでIPアドレスが変わってもコネクションが切れなくなるといったメリットも享受できます。
HTTP/3の名称
Googleが現在使っているQUICとIETFで標準化を行っているQUICはとこどころ異なっており互換性はない。区別して前者をgQUIC、後者をiQUICと呼び分ける。(参照: gQUICのiQUICへの移行について)
実験的なプロトコルであったGoogleのQUICに対して、標準化されたQUICは別の名称をつけるという議論もありましたが、名前を変えずQUICとする方向になっています。
(GoogleのドキュメントではQUICを「Quick UDP Internet Connections」としていますが、IETFのドキュメントではQUICはQUICであり何かの略語ではないとしています)
名前のもう一つの混乱としては、IETFの"QUIC"はトランスポートプロトコルとしての名称であるが、HTTP over QUICを指していると思ってる人がいるところである。IETFで標準化しているQUICはトランスポートプロトコルであり、アプリケーションプロトコルはHTTPに限定されない。
このような混乱を避けるため、QUIC-the-HTTP-bindingに別名をつけQUICから明確に区別できるようにしないかという議論が出ています。
IETF QUIC WG チェアのMark氏より「Identifying our deliverables」というメールがMLに投稿されています。このメールではHTTP/3という名称が提案されています。
これは、現在開催中のIETF103でも議論される予定ですが、HTTP WGとQUIC WGでのコンセンサスが得られればその方向で進む可能性が強くなるでしょう
(補足: HTTP/3と呼ぶコンセンサスが得られました)
ストリームとフレーム
QUICではトランスポートレイヤにストリームを持つため、HTTP/2であったストリーム管理の多くはなくなっています。例えば各ストリームのフロー制御はなくなっています。QUICレイヤで提供されるストリームをどのように使うかが、HTTP/3の仕様では定義されています。それに合わせてHTTP/2で使用していたフレームも一部なくなったり、新しく増えたフレームタイプもあります。それぞれのフレームのフォーマットも変更されています。
HTTP/3で定義されるフレームは以下の通り
- DATA
- HEADERS
- CANCEL_PUSH
- SETTINGS
- PUSH_PROMISE
- GOAWAY
- MAX_PUSH_ID
- DUPLICATE_PUSH
- Reserved Frame Types
ストリームの扱いに関しては、通常のHTTPリクエスト/レスポンスは双方向ストリームを使用しますが、SETTINGSなどを送信する制御ストリームやサーバプッシュに使われるプッシュストリームなどは単方向ストリームを使用します。
また、サーバプッシュはPUSH IDと呼ばれる識別子で識別されます。このPUSH IDを用いて、パケットロスを見越して複数回同じプッシュを行うということができます。また、プッシュを中断するためのCANCEL_PUSHフレームや、プッシュ数を制限するMAX_PUSH_IDフレームなどが追加されています。
プライオリティ制御
(補足: Priorityの機能は複雑であり汎用的なPriority制御が難しいという判断により、draft-23でHTTP/3の仕様からは外され、オプショナルな機能となりました。)
HTTP over QUICでもHTTP/2のようなストリームに対してWeightとDependencyを設定することで優先度を設定します。
HTTP/2のプライオリティ制御では、ストリームは実際には使用せずプライオリティ制御のためだけに特定のストリームを使用できました。
例えば下記のようなHTTP/2 のdependency treeにおいて、ストリーム3,5,7は各リソースの優先度をグルーピングするためだけに使用されておりました。
しかし、QUICのストリームは各ストリームタイプでID順に使用していくことになっています。そのため、HTTP/2で行っていたような、実際にはデータの送受信には使用しないストリームをプライオリティ制御のグルーピングのために使用できません。
そのかわりに、HTTP over QUICではPlaceholderというそれ用のIDを用意しておき、そこに対して依存関係を指定するようになっています。また、ストリームID 0は今回はdependency treeのルートではないので明示的にルートしめす値が用意されています。
また、HTTP/2のときにあった問題として、特定のストリームがクローズしていても将来優先度処理で使用される可能性があるのでいつ状態(weight)を破棄していいか分からなかったという点です。HTTP over QUICでは非アクティブなストリームに関する、dependency treeの枝刈りに関する文書が加わり、クライアントは非アクティブなストリームに依存するようなストリームを作成すべきではなくなりました。
QPACK
HTTP/2ではHTTPヘッダ圧縮の仕組みとしてHPACKを使用していました。HTTP over QUICでは、各ストリームの順序が入れ替わる可能性があるため、クライアントが送信したHTTPリクエストの順番の通りにサーバが受信するとは限らなくなりました。この場合、HPACKの動的ヘッダテーブルの更新はクライアントとサーバで状態を正しく動悸することができません。これをそのまま正しく同期しようとおもうと、正しい順番に並び替えるための待ち時間が発生してしまいます。
そこで、HTTP over QUICではQPACKと呼ばれるヘッダ圧縮方式を使用します。この方式では、上記の問題が改善されています。
また、HTTP/2の静的ヘッダテーブルは当時のヘッダ利用状況に基づき作成されましたが、alt-svcヘッダの使用頻度が上がっているなど状況が異なっています。
https://github.com/quicwg/base-drafts/pull/1355 で示されるよう、静的ヘッダテーブルも大きく更新されています。
QUICサーバのディスカバリ
(alt-svcは HTTP/3独自の仕組みではないが)
HTTP/3ではポートは決められていません。下記の方法でサーバ側からポートも含め指定します。
HTTPレスポンでalt-svcヘッダを用いることで、このオリジンのページを別プロトコル(別サーバ)で提供できることをクライアントにアドバタイズします。
クライアントがHTTP/3に対応していればそこに接続してきます。
Alt-Svc: h3=":50781"
ここで指定する識別子も、名称が変わった場合変更されます。
そのた
その他トランスポートレイヤの変更に伴い、下記の部分について変更が入っている
- CONNECTメソッドによるトンネリングとエラーについて
- エラーコード (まちがったストリームタイプの使用など)
- コネクションの確立と切断