BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース Cloudflare社、quicheの輻輳制御バグを解決した手法を公開

Cloudflare社、quicheの輻輳制御バグを解決した手法を公開

原文リンク(2026-06-26)

Cloudflare社はこのほど、輻輳制御アルゴリズム「CUBIC」のRust実装における問題の発見と修正について明らかにした。この問題は、接続開始直後に大量のパケット損失が発生した場合に、輻輳制御が正常に回復できなくなっていた。

この問題は、同社が処理するトラフィックの大部分においてクリティカルパス上に位置しているオープンソースのQuick UDP Internet Connections(QUIC)実装「quiche」に影響を及ぼしていた。チームはこの問題の原因を、TCPの実際の課題を解決するためにLinuxカーネルへ導入された変更までさかのぼって突き止めた。

Cloudflare社のシステムエンジニアであるEsteban Carisimo氏と、プリンシパルシステムエンジニアのAntonio Vicente氏は、この調査はイングレスプロキシの統合テストパイプラインで発生した予期しない障害の報告をきっかけに始まったと説明している。失敗したすべてのテストには共通点があった。それは、接続の初期段階で大量のパケット損失が発生するシナリオにおいて、CUBICの挙動を評価していたことである。

Carisimo氏とVicente氏が説明するように、CUBICをはじめとする損失ベースの輻輳制御アルゴリズムは、次の基本的な前提に基づいて動作する。

(1) パケット損失が発生しない限り、送信レートを上げる(つまり、帯域幅の利用率を段階的に増やしていく);(2) パケット損失が発生した場合、損失ベースのアルゴリズムはネットワークの容量を超過したと判断し、送信側は送信レートを引き下げ(つまり、帯域幅の利用率を下げる)なければならない。

問題をより深く理解するため、チームはシミュレーション環境を構築した。この環境では、localhost上で動作するQuicheのHTTP/3クライアントとサーバーを用い、輻輳制御アルゴリズムとしてCUBICを使用した。また、往復遅延時間(RTT)は10ミリ秒に設定した。クライアントはHTTP/3経由で10MBのファイルをダウンロードする。この際、最初の2秒間にランダムな30%のパケット損失を発生させた。テストは通常4〜5秒程度で完了する想定であり、10秒のタイムアウト設定は十分に余裕があるように思われた。

シミュレーションテストの結果は、統合テストパイプラインで発生していた障害を裏付けた。100回単位で複数回実行したところ、約60%のケースで10秒のタイムアウトまでに処理を完了できなかった。

チームは、問題のある挙動を詳しく分析するため、実装に計測用コードを組み込み、問題発生時の詳細情報を収集した。その結果、パケット損失が発生した期間の終了後も、輻輳ウィンドウ(congestion window)が期待どおりに増加せず、回復の兆候が見られないことが判明した。さらに、計測結果からは、パケット損失のない期間にもかかわらず、CUBICが「輻輳回避(Congestion Avoidance)」状態と「リカバリー(Recovery)」状態の間を高速に行き来していることが判明した。より具体的には、約6.7秒の間に999回もの状態遷移が発生していた。これは約14ミリ秒ごとに1回の遷移が起きていた計算になる。チームは、この間隔が設定した接続のRTTである10ミリ秒に不自然なほど近いことから、異常な挙動ではないかと疑った。

"不具合発生時の累積パケット損失量と輻輳ウィンドウサイズの関係。出典:Cloudflare社ブログ"

チームは、より広範な問題ではないことを確認するため、CUBICの代わりに別の損失ベース輻輳制御アルゴリズムであるRenoを使用してテストを実施した。その結果、Renoではシミュレーションテストが100%成功した。これにより、問題はCUBIC固有のものであることが明らかになった。

チームによると、CUBICにおけるアイドル時間の計算方法が原因で、実装が終わりのないリカバリーループに陥っていたという。このループは、ノイズの多いスロースタート中に受信したACKパケットによって、ネットワーク上を転送中のデータ量(in-flight bytes)がゼロになった際に発生していた。著者らによると、輻輳ウィンドウの最小値である2パケットの状態では、アイドル期間を最適化する仕組みが自己成就的な状態に陥る。その結果、アプリケーションはリカバリー状態にとどまり続け、回復終了時刻が常に遠い未来へ再設定され続ける。この状態では輻輳ウィンドウの拡大が事実上阻害され、終わりのないリカバリーループに陥っていた。

RedditユーザーのRelevantKnowledge485氏によると、同様の問題に遭遇した人はほかにもいたという。

私たちも、高頻度タイマーに依存するワークロードで非常によく似た問題に直面しました。Cステート遷移によって予測不能なレイテンシスパイクが発生していたのです。このデバッグ手法は見事です。カーネルの電源管理判断とプロトコルレベルの再送挙動との相関を分析した点が非常に優れています。

著者らによると、この調査は最終的に良い結末を迎えた。そして、問題の挙動自体は非常に複雑だったものの、その解決策は驚くほどシンプルなものだったという。「幸いなことに結末はハッピーエンドでした。このループを断ち切る修正は、実質的に1行に近いエレガントなものでした」と著者らは記している。

チームは、アイドル時間を最後に送信したデータ時点からだけでなく、最後にACKを受信した時点からも計測するよう実装を変更した。

"修正後の累積パケット損失量と輻輳ウィンドウサイズの関係。出典:Cloudflare社ブログ"

この修正によりループは解消され、輻輳ウィンドウも期待通りに回復するようになった。結果、テストの合格率は100%まで改善した。

作者について

この記事に星をつける

おすすめ度
スタイル

特集コンテンツ一覧

BT