QUICにおけるヘッダ圧縮の提案仕様 QPACK(旧QCRAM)

20190408追記
最新版について記事を書きました
asnokaze.hatenablog.com

QUICとヘッダ圧縮

HTTP over QUICの仕様は現状、HTTP/2と同様HPACK(RFC 7541)を利用してHTTPヘッダの圧縮を行う。

HPACKはHTTP/2を想定としており、トランスポートはTCPであり順番通りにパケットが届く想定の仕様となっている。具体的には、動的テーブルにおいてエントリーの追加やそれに伴う暗黙的なエントリのエヴィクションが発生してもエンコーダ側とデコーダ側で状態が同期できるのがHPACKである。

QUICはUDPを使うとともに、同一のストリーム上でのみデータの順番が保証される仕組みになっている。これによってパケットロスが他のストリームをブロックすることがなくなるというメリットがあるが、前述の通りHPACKを使っている限りヘッダのデコードは順番通りにしか処理が出来ない。結局としてパケットロスがHTTPヘッダのデコード部分についてはブロックする可能性が出てくる。

QUICの標準化を行っているIETFのQUIC WGでは、HTTP over QUICで使用する新しいヘッダ圧縮の方式が議論されている。
現在案は2つある

  • QPCAK: HPACKのワイヤフォーマット自体変更する
  • QCRAM: HPACKのワイヤフォーマットを維持する

QPACKについては、以前ブログに書いたとおりです(仕様はブログを書いてから更新されているため注意)
asnokaze.hatenablog.com

今回はQCRAMについて説明する

QCRAM

QCRAMは「Header Compression for HTTP over QUIC」という仕様であり、QPACKと区別してQCRAMと呼ばれる。仕様の著者はGoogleのCharles 'Buck' Krasic氏である。

QCRAMではHPACKのワイヤフォーマットにプレフィックスを付ける形で、動的テーブルの参照におけるヘッドオブラインブロッキングを緩和する。

順番が保証されない状態で、HPACKの動的テーブルを使うときの問題点は主に2つある

  • Insertion Pointよりエントリが挿入されることで、その他のエントリも index値 が変化する
  • エントリが挿入されることによって、テーブル上限に達した場合は Dropping Point より古いエントリが削除される
           <----------  Index Address Space ---------->
           <-- Static  Table -->  <-- Dynamic Table -->
           +---+-----------+---+  +---+-----------+---+
           | 1 |    ...    | s |  |s+1|    ...    |s+k|
           +---+-----------+---+  +---+-----------+---+
                                  ^                   |
                                  |                   V
                           Insertion Point      Dropping Point

https://tools.ietf.org/html/rfc7541#section-2.3.3


QCRAMではHEADERSフレームとPUSH_PROMISEフレームにおけるHPACK形式で表現されるヘッダブロックに以下のprefixを追加します

       0 1 2 3 4 5 6 7
      +-+-+-+-+-+-+-+-+
      |Fill       (8+)|
      +---------------+
      |Evictions  (8+)|
      +---------------+
  • Fill: 現在の動的テーブルのエントリー数
  • Evictions: エヴィクション回数

それぞれHPACKにおける整数表現が使用されます。また両方を足すと今まで挿入したエントリ数となります。

f:id:ASnoKaze:20170805204704p:plain

このprefixを使えば、挿入によってindex値がずれていたとしてもEvictionsとFillの情報から指し示しているindexが求められます。指し示すindex値がすでに到着して入ればそれを使用します。そのindex値が指し示すエントリがまだ挿入されていなければ待つことになります。

また、エヴィクションに関してもエンコーダが明示的にエヴィクションされた回数を送ってくるので、デコーダ側は自身のエヴィクション回数と比べて多ければエヴィクション出来ることになります。(保持する上限は別途実装依存となる)

その他

QCRAMの仕様はprefixの仕組みが大きいがそれ以外にも幾つかの支持がある。
例えば、QUICレイヤのAckをHTTPレイヤに伝えることで、相手に届いたことを確認してからそのindexを使うように進めている。また、動的テーブル上のエントリを再登録するIndexed Header Field with Duplicationなどの定義が与えられている。