「Debugging Modern Web Protocols with qlog」の紹介

Robin Marx氏の論文「Debugging Modern Web Protocols with qlog」の紹介です。何かおかしなところがありましたら原文を確認いただけると。

概要

本論文では「Debugging Modern Web Protocols with qlog」では、QUICのデバッグ用に作られたqlog/qivsに対する

①QUICの開発者がqlog/qvisを採用したいと思うか?

②qlog/qivsがQUICのデバッグに必要不可欠なものになるのか?

③qlogはスケールするのか?

という3つの疑問への回答を、実装者へのサーベイ結果と著者の経験をもとに議論している。

論文: https://qlog.edm.uhasselt.be/anrw/files/DebuggingModernWebProtocols_Marx_ANRWReview_23apr2020.pdf

著者のページ:

qlog.edm.uhasselt.be

qlogのgithub:

github.com

1章 Introduction & Motivation

背景

QUICは0-RTTハンドシェイクやコネクションのマイグレーションなど多くの特徴があるが、とても複雑になっている。著者の実装経験から、デバッグとシステムの妥当性を確認するためのツールが必要であることが明らかになった。それらのツールは理想的には、コードベースをまたいで再利用可能なフォーマットが望ましい。

wireshark、tcptrace、captcpなどの既存のツールは、ワイヤーイメージを直接使用している。QUICでも同じやり方は可能である。しかし、初期の実装の時点においては、ワイヤーイメージでは複雑なコンポーネントデバッグするための重要な内部の情報が抜け落ちてしまうため最適とは言えない。そういった内部の情報は、コマンドラインのログでしか手に入らないため実装依存になり、解析が難しい。

その課題に対応するために、著者は構造化されたエンドポイントのログフォーマットであるqlogを提案した。qlogはJSONベースで、QUICとH3のイベントと内部の状態(なぜパケットがロスしたのか、データがレイヤー間をどのように移動したのか)を標準化している。著者は、qlogに適合したツールとしてqvisも実装した。

qlogに対する3つの疑問

ツールを実装した段階では、以下の3つの疑問に正確にこたえることは難しかった。

①QUICの開発者がqlog/qvisを採用したいと思うか?

②qlog/qivsがQUICのデバッグに必要不可欠なものになるのか?

③qlogはスケールするのか? qlogは、開発初期のデバッグ用途だけではなく、大規模なデプロイをしたときの課題の解析に使えるのか?

QUICのトラブルシューティングを行うアクターは、エンドポイントのオーナー(ロードバランサーCDN、オリジンサーバーなどを管理する)と、ネットワーク事業者(中間のネットワークインフラを管理する)の2つが考えられる。 従来ではデバッグにipfixやnetflowなどの低レイヤーのツールを使っていた。しかし複雑な問題のデバッグのためには、トランスポートレイヤーの情報も必要になる。TCPではキャプチャをする方法が主流である。レイテンシーやパケットロス率などは、TCPメタデータ(シーケンス番号とACK)などから推測されて、問題の解決に使用される。

しかし、QUICでは、TCPTLSでは見えている情報がend-to-endで暗号化されているため、その方法を適用するのが難しい。なので、QUICのトラフィックを解析するにはライブで復号するか暗号化されたものをあとで復号するために保存する必要がある。

後者は、巨大なストレージが必要になる(TCPの場合は暗号化されていない最初のヘッダの一部を保存しておけばよい。)。 さらに、プライバシーとセキュリティの問題も発生する。コネクション毎の暗号化キーを保存することで短命なキーを使うことのメリットが失われる。さらに、トランスポートのメタデータだけではなくアプリケーションのデータすべてが復号されてしまう。また、ネットワーク事業者がこれを可能にするために、エンドポイントのオーナーは復号化のキーを共有しなくてはいけない。

この状況への解決方法として、暗号化されない情報をQUICパケットのヘッダに追加することが考えられる。しかし、WGは慎重で、1ビットのspin bit さえも大きな議論を呼んでいた。ロスビットもQUICのコアに入るかはまだ明確になっていない。

別の解決方法等して、qlogを使う方法が考えられる。暗号化されたpcapと違い、qlogのログには必要なメタデータだけが含まれる。それによって、ストレージや、プライバシーにかかわる問題は解決される。更に、内部のアプリケーションの状態も含めることができるので問題の根本分析にも役に立つ。また、eBPFによってTCPの内部状態を引き出すことで、TCP+TLS+H2にもデバッグの機能を提供することができる。しかし、これらが実現するためには、qlogが本当にスケールするかを判断する必要がある。

2章では、qlogの採用とスケーラビリティについて議論する。現時点で、CloudFlare、 Mozilla Firefox、 Node.js、Facebookを含む12/18の実装者がqlogを実装している。 28の実装者と研究者に、qlogを取り込んでいる理由とどのように使っているかをサーベイした。

また、qlogがスケールかどうかを確認するために、Facebookのエンジニアにインタビューを行った。Facebookでは、qlogとqvisを、インターネットスケールで、毎日300億件のイベントが発生するようなQUICとH3のモバイルアプリケーションのファインチューニングのために使用している。

3章ではqivsがどのようにデバッグに使われているかを紹介する。ここではmultiplexing、packetization、congestion control、multipath extensionで実際に直面した課題を説明する。

4章では、著者のアプローチはqlog/qvisの実用という可能性を発揮しているが、大規模な実用化に向けてはまだ道のりがあると結論付けている。

本論文では付録としてのスペースがないため、調査の詳細、ソースコード、結果、可視化、その他の成果物はすべてウェブサイトで公開されている。

2章 qlog usage in practice

QUICのコミュニティに対するサーベイ結果から、qlogが採用されている理由と課題について説明をする。

qlogが採用されているのには、2つの大きな理由がある。

①使いやすさ、ツールが作れること、可視化(3章で説明)

②フォーマットの柔軟性

まずは、フォーマットの柔軟性が以下の4点によって実現されることを説明する。

1. custom event の定義

qlog では、custom eventを定義することができる。

それぞれのqlog イベントは、timstamp、category (transport)、event type (packet_sentなど)、そして、 event_typeに固有のデータ(送信したパケットサイズ、ヘッダーフィールド)によって定義されている。

qlog のドラフト では主に、QUIC+H3で使うカテゴリー、タイプ、データレイアウトを定義している。

qlogはjsonで定義されているので、修正、拡張が簡単にできる。なので、実装に依存したイベントを定義することもできる。 また、ACK Frequency、Datagram、Lossbit、マルチパスなどのQUICの拡張に対するデバッグも可能となる。

また、qivs では、qlogやqivsの更新を待たずに、ほとんどのカスタムイベントを表示することができる。

逆に、実装する人は特定のイベントをログしないように実装することもできる。それによって、ファイルサイズの削減や、イベントの実装を必要なものにすることができる。

2. QUIC+H3に限らない柔軟性のサポート

qlog は他のネットワークプロトコルをサポートすることもできる。

DNS-over QUIC はすでに実装されている。WebTransportやMASQUE、QUIC tunnel への適用も考えられている。

また、著者はTCP+TLS+H2のスタックのサポートも進めている。https://github.com/quiclog/qvis/blob/master/visualizations/src/components/filemanager/pcapconverter/qlog_tcp_tls_h2.ts

TCP+TLS+H2のスタックのサポートでは、復号したpcapをqlogのイベントに変換する。そして、輻輳制御ウィンドウ、RTTの推定値など細かい内部のTCPの状態を、eBPFを使って取得する。そして、両方のデータを一つのqlogファイルに統合する。同時に、H2の内部情報を取得するが、それなしでもTCP+TLS+H2をQUIC+H3と同じよう解析することができる。

3. qlogのファイルはプロトコルに依存しない "container" の構造

qlogはプロトコルに依存しないので、ファイルには追加のメタデータを含めることができる。 これによって、複数の独立したトレースを一つのqlogファイルに集めてqivsで表示することできる。 例えば、クライアント、ロードバランサーCDN、オリジンサーバーなどの情報を1つのファイルに入れて、qvisを使ってシーケンス図を表示することができる。 これによって、多層な構造な場合でも、エンドツーエンドの振る舞いも評価することができる(Facebookは実験を始めているらしい)。

4. フォーマットがjsonでmachine readableだから、loggingや可視化以外にも使うことができる

aioquicやmvfstのようにユニットテストのパイプラインに組み込んで、qlogの出力のイベントからプロトコルの振る舞いの妥当性を判断しているユーザーもいる。 また、QUIC TrackerやQUIC-Network-Simulatorなどでは相互接続テスト結果の妥当性の確認で使うことも検討されている。 Facebookはqlogをリレーショナルデータベースに入れて、特定の振る舞いの解析などに使っている。例えば、パケットロストのイベントなどの振る舞いをクエリーにして検索することができる。

qlogを使わない理由

qlogを使っていない実装者がなぜ使っていないかも分析している。

GoogleMicrosoftは、独自のフォーマットを持っている。

また、他にデバッグ性の無さに困ってはいるものの、高い優先度で採用はしていない人たちもいる。そのような人たちは、最初の導入とその後のメンテナンスの両方にかなりの時間がかかることを懸念している。

しかし、これは著者の経験とは矛盾している。PQUICにおける著者のqlogの統合は分離して行った。そして、追加のプラグインが簡単に新しいイベントを注入できるように柔軟性を持たせていた。

jsonはスケールしないのではという議論

jsonを選んだのは、フレキシブルで、ほとんどのプログラミング言語でサポートされているからである。

大きい会社は、フォーマットが冗長(巨大なファイルにつながる)で、デシリアライズシリアライズが製品で使うには遅すぎることを懸念している。彼らは、jsonの利点がなくなっても最適化されたbinary formatを使うほうが良いと提唱している。

Facebookは唯一qlogを大規模にデプロイしている。 Facebookによると、元々使っていたバイナリのフォーマットよりも、qlogは2、3倍大きくて50%もシリアライズに時間がかかる。それでも、彼らはオーバーヘッドがサーバーサイドで管理可能であると考えている。

Facebookでは、ランダムに選ばれた10%のQUICの接続から毎日300億のqlogのイベントを記録させるところまでスケールさせている。

対照的に、クライアント側では、ユーザーが携帯ネットワークなどを使っているので、巨大なqlogのファイルを全部アップロードすることは難しい。 それでもFacebookは柔軟性を失うならバイナリフォーマットには移行しないほうが良く、qlog専用のjsonリアライザーを作ればCPUのオーバーヘッドは減らせると考えている。

qlogが柔軟性と効率性を両立させるソリューションから恩恵を受けることは明らかです。著者はいくつかの方法を検討した後に、2つの最適化モードを用意した。

一つ目は、H3のQPACKのように、繰り返されるものは論理的に圧縮する方法である。

二つ目は、CBORをqlogの圧縮に使う方法である。

参考として、500MBのダウンロードのqlogは通常では276MBだった。そこに2つの最適化を適用すると、91MBになる。ここからさらに圧縮をすると15MBになる。これに対してbinaryのprotobufは圧縮後で14MBとなりほぼ同等になる。

これに対して、圧縮されたpcapは500MBを超えるので、代替としてスケールは難しい。

f:id:neko--suki:20200429152539p:plain
Table 1

一方で、qivsはそのような数百MBのJSONをロードできるようにスケールできる。

3章 Visualization Case Studies

ネットワークプロトコルの振る舞いととクロスレイヤの相互作用は複雑で、テキストのログから見分けるのは難しい。 逆に、簡単な可視化でも問題への洞察が明らかになることがある。

サーベイの結果、qlogを使うには、custom visualizationが作りやすいことと、qvis のツールが再利用できる点があることが一つの主な理由として挙げられる。

現在、qlogでは5つの機能が実装されている。

本章では、16のQUIC+H3スタックと5つのTCP+TLS+H2スタックの実装と徐者自身の経験から、バグや非効率性の発見にどのようにqlog/qivsが使われていたかについて述べる。

実際のqivsで可視化をしている様子は以下のリンクから見ることができる。

qlog.edm.uhasselt.be

3.1 Stream multiplexing and prioritization

QUICなどのモダンなプロトコルでは、ストリームをコネクション上で多重化する。多重化は、Sequential(順番に送信)やRound-Robin (RR)などの複数方法で実装されている。また、多重化されたストリームは優先順位付けをされる。しかし、これらを正しく実装するのは難しい。その結果、優先順位が正しくなくなりウェブページのロードの性能が落ちてしまうことがある。

qivsは、H2とH3のペイロードがリソースを運んでいる様子をプロットができる。 多重化の様子を横軸方向にフレームを並べることで可視化することができる。色の違いがストリームの違いを表している。

f:id:neko--suki:20200429100836p:plain
Figure 1

(補足: この例は、おそらく著者の別の論文に書かれている10個のリクエストを同時に発行している例である)

①②は、色が頻繁に変わることからRound-Robinによって多重化を行っていると判断できる。 一方で同じ色が長く続く③はSequentialに多重化をしていることが分かる。

ストリームの多重化の可視化によって想定していない振る舞いの判断などもできる。 ①はフローコントロールの影響で最初は想定しない動きをしていることが分かる。 ③は意図せずLast-in-First-Outになって知っていることが分かる。

また、qivsではQUICの再送も可視化することができる。

TCPでは、ロスしたパケットは最高優先度で送信されるが、QUICは高い自由度がある。 例えば、③はTCPに似ているが、②は再送を通常のデータと同じ扱いにしている。一方で、①は再送の時はmultiplexing の方法を変更していることが分かる。

3.2 Packetization and Framing

3.1 はHTTP のDATAフレームのレイヤーについて扱っていたが、より低いレイヤーを扱うことができる。

例えば、H2のフレームは1または複数のトランスポートのユニットに格納される。それが、複数のTCPのパケットに分散される。 H3のフレームはTLSレコードの代わりに、QUIC Streamフレームにパッキングされる。そして最終的にQUICパケットに格納される。

分割されることはオーバーヘッドになるため、どのようにユニットとサイズが組み合わされるのかはプロトコルの効率に影響を与える。

更に、分割の仕方はセキュリティのリスクも起こす可能性がある。もしHTTPフレームのエッジが下のレイヤーのエッジにアラインメントされているとすると、攻撃者はHTTPのリソースのサイズを推測できる。

qivsのpacketizationは、水平方向にそれぞれのプロトコルレイヤーのユニット表示することで、ペイロードとオーバーヘッドを可視化することができる。ペイロードとオーバーヘッドは、水平方向の白い領域を見ることで違いを見分けることができる。

f:id:neko--suki:20200503093612p:plain
Figure 2からの抜粋

f:id:neko--suki:20200429161540p:plain
Figure 2

別の色は、別のユニットエッジを表している。

一番上の行のストリームIDは3.1と同じものを表す。これによって、H2/H3 がファイルをDATAフレームに格納しているのかがわかる。

A

Aはズームアウトした図を表している。

青のHTTP2のフレームは、赤のTLSのレコードと同じサイズである。TLSのレコードは、それらのエッジが正確にアラインメントされている。 しかし、1.1MBののちに、大きなTLSレコードに変更されている。 更に、それぞれのファイルはより小さいTLSレコードで終了する。これによって攻撃者がファイルサイズを推測しやすくなる。

B

Bの図では、Aに対してズームインをしている。

HTTP レイヤーは、新しい 9 バイトの H2 フレームヘッダが書き込まれるたびに、すべての未処理のデータを新しい TLS レコードにフラッシュさせる。 これでは効率が悪いだけでなく、リソースサイズが明らかになってしまう。これはサーバー側のバグと考えられる。

C

Cは、1000個の10バイトのファイルをリクエストするストレステストの結果を表している。 実装上、可能な限りを多くのフレームを一つのQUICパケットに入れ込むことが予期されていた。しかし、一部で意図せずに小さいQUICパケットが生成されていることが分かる。 この結果から、実装者は正しくbundleできるように修正することができた。

D

ここでは、おおよそ10番目と30番目のパケットを送信した後に、平均のパケットより小さいパケットの送信が起こっている。

この理由はQUICの仕様ではQUICの輻輳ウィンドウはパケットでは表現されず(TCPとは違い)バイトで表記されることにある。 Dの実装では、小さいサイズのパケットを生み出すことになったとしても使えるバイト数を使い尽くそうとしている。

著者の調査によると、興味深いことに、半分以上のQUICの実装が仕様に反してこの非効率性を迂回している。 そしてTCPと同様に、そのCWNDのサイズを最大のパケットサイズにまで切り上げている。

E

Eでは、1バイトのH3のペイロードが観測できる。

このエラーは、QUICのパケット番号が可変長だから発生している。 (64未満は1バイト、16383未満は2バイトで表される) この仕様は、再送の時に、ストしたQUICパケットに新しいパケット番号が割り当てられるときに問題になることがある。

このパケット番号を1バイト大きくする必要がある時には更新されたパケットは最大のパケットサイズを超えてしまうが、それは許されていない。

多くのQUICの実装は、完全に再フレーム化するが、Eのように、この問題は十分にまれだと判断し、非効率ではあるが実装をシンプルに保つためにこのままにしている実装者もいる。

この例のように、難解なふるまいの可視化と解釈も可能になる。

将来の拡張など

例えば、MASQUE、QUIC tunnelなど、QUIC over の新しいアプリケーションプロトコルを採用したときにも使える。 qvisによって、非効率な部分の識別やセキュリティの問題、複雑なインタラクション(QUICとtunneling プロトコルが同じ輻輳制御ロジックを使わないような場合)などにも対応できる。

3.3 Congestion Control

輻輳制御は数十年進化し続けていて、現在でもアクティブな研究開発が行われている。しかし、バグがいまだに見つかっている。 また、COPAやBBRv2などの新しい手法の開発やfine-tuningが行われている。

QUICはユーザースペースの実装なので、今後実験に対してTCPよりオープンなることが予想される。

輻輳制御は、正しく実装するのが複雑なコンポーネントの一つであることが知られている。

これは今回のサーベイでも反映されており、qlogに基づいてカスタムビジュアライゼーションを作成する主な理由として輻輳制御のデバッグがあげられている。

qlogではより理解可能な輻輳制御のグラフを表示する。このグラフは、送信したデータと受信したACKをタイムラインで表示させることができる。 輻輳ウィンドウ、送信中のバイト量、接続とストリームレベルのフローの制限、RTTも同様に表示させることができる。

Figure 3 は可視化されたものの一部分を表示している。

f:id:neko--suki:20200429164605p:plain
Figure 3

Figure 3ではペーシングがある場合とない場合の輻輳制御の振る舞いを載せている。

ペーシングとは、パケットを短いバーストで送信するのではなく、RTTでパケットを分散して送信する方法で、一般的にはパケットロスを減らすために考えられている。

実際に、qvisとカスタムツールで、いくつかのバグが発見された。

FacebookはBBRが、probe RTT に正しい時間に移行していないことを発見した。また、RTTの計測のエラーから大陸間のデータセンター間の大規模デプロイのペーシングの問題も識別をした。

他には、QUICのハンドシェイクの間の再送に関連するバグを発見した事例もある。

また、著者のPQUICの開発では、mininetがデフォルトでは無限のキューのサイズを持っていることを発見した。これは、スロースタートフェーズと全体で、RTTが増え続けていることが可視化されたために発見することができた。さらに、とても短いカーネルのフリーズが、明確に切れ目として確認できるようになった。また、PQUICのWestwoodとBBRの実装の正しさの確認にも使った。

最後に、輻輳制御の難しさに対して、qlogとqvisはjunior researcherや学部の学生でさえも、輻輳制御に関連した貢献ができるようになった。これは、幅広い利点を示している。qlogとqvisは、近代的なプロトコルの振る舞いを学校や会社でも教えることができることを意味する。

3.4 Multipath QUIC

QUICの一つの特徴的な機能に、IPとポートの移行による接続のマイグレーションがある。

Multipath QUICでは、同時に複数のネットワークパスを同時に使えるようにuniflowとしてモデリングすることで、この特徴を生かしている。

MP-QUICの実装は4つのキーコンポーネントを活用している。それぞれがQUICのパケットの送信と処理のロジックに複雑さを追加している。だから、内部の状態の正しいデバッグを必要としている。

著者は、Plugnized QUIC (PQUIC) を開発する際に、qlogの柔軟性を活用し拡張をした。

マルチパスに関連した状態を表すcustom qlog event の追加と、既存の接続レベルのイベントへの uniflow ID の追加を行った。そして、qivsに関連する2つツールを開発した。

1つ目は、Figure 4. のようなqivsのシーケンス図の簡易化である。このツールは、パケットロスとリオーダーを表示することができる。そして、色のついた矢印が異なるuniflow を表している。また、パケットの中身を矢印の上のテキストに表示させている。

f:id:neko--suki:20200503101930p:plain
Figure 4

2つ目は、qlogのイベントを表示することができる汎用的なタイムラインツールである。例えば、パスごとあるいは全体の輻輳制御の値を表示させることができる。

著者はこの2つのツールを使って4つのキーコンポーネントデバッグした。

一つ目のコンポーネントはパスマネージャである。パスマネージャは、リンク障害検出ヒューリスティックを使用して、潜在的なネットワークパスのうち、実際に使用可能なものを決定する。著者の実験では、リンク障害が発生した時間を、パスマネージャがuniflowをあきらめて別のuniflowをプロービングする時間と一致させるヒューリスティックな手法で、偽陽性を検出し修正を行った。

二つ目のコンポーネントはパケットスケジューラーである。いくつかの uniflow の中からパケットを送信するパスを選択する。ツールを使うことで、パケットスケジューラーが、リンク障害が検出されてすでに使えないuniflowを選ぼうとしているのを発見した。

この問題は、uniflowごとの色付けによってすぐに発見された。

三つ目のコンポーネントはフレームスケジューラーである。選んだ uniflow をもとに、連続したフレームからパケットを生成する。Stream FrameのStream IDを見ることで、path-awareなフレームスケジューラーの評価を行えた。

四つ目のコンポーネント輻輳制御のコントローラーである。それぞれのネットワークパスごとに異なる状態を維持するために採用されている。

非対称性なパスを持つシナリオでそれぞれのパスごとにRTTをプロットすることで、MP_ACKフレームが間違って扱われていることを発見した。タイムラインのプロットは、RTTの評価値から2つの最頻値を可視化させた。そこから明らかに2つのパスが使われていることが明らかになった。この発見が最新のMP-QUICの双方向のパスを uniflow に変更する設計変更への動機になった。

4. Conclusion & Challenges

この論文では、最初に説明した3つの疑問のうち2つに回答している。

一つ目の質問に対して、QUICコミュニティ(FacebookMozilla、Cloudflareを含む)のかなりの部分が、初期実装のデバッグと、より大規模な(予定されている)デプロイのサポート(大企業の参加者の60%)のために、qlogとqvisを採用していることが明らかになった。

二つ目の質問に対して、この論文では、著者や他のグループがqlogとqvisを使って得た結果のほんの一部について議論をしている。それでも、著者のアプローチは、実装、デバッグ、そして、QUIC+H3のみに関わらず他のプロトコルの改善にも関わる。

さらに、QUICの複雑なふるまいを簡単に観察できる能力は、新規の参加者の教育やさらなる学術の研究を容易にすることができる。

三つ目の質問に対して、構造化されたエンドポイントのログはスケールすることが可能で、パケットキャプチャを置き換えることができるといえる。 しかし、現状では部分的に答えただけになっている。

著者は、Facebookのデプロイメントから、エンドポイントではスケールが可能であると感じている。またqlogにそれを簡単にするような変更を加えた。それによって、それらの効果は証明されたと考える。

しかし、ネットワーク事業者にはqlogを簡単に作成する能力がないため、これが直接効果を発揮するとは考えにくい。潜在的には、エンドポイントのオーナーが、qlogを中間者と共有することが考えられる。しかし、そのためには追加のログの転送、保存、収集が必要になる。また、一番重要なのはアクセスコントロールとプライバシーを担保するインフラが必要になる点である。

そのため、著者はこの結果が将来のIETFの議論で他の方法(ネットワーク事業者のユースケースのためにQUICにプレインテキストのメタデータを加えること)との比較に役立つとよいと考えている。

最後に、著者はIETFがより多くのプロトコルにqlogを適用することを検討するのに役立つことを期待している。

感想

qlog/qvis がかなり広く採用されていることが分かりました。

私自身も実際にqlog/qvisを使って、QUIC上で動かすアプリケーションのデバッグを行った経験がありとても助かりました。

使いやすいツールが用意されることで、QUIC本体を実装する人に限らず、その上位のアプリケーションの開発者がQUIC自体をより簡単に使えるようになり広く使われるようになるのではないかと思います。