1 ポイント 投稿者 GN⁺ 2025-09-28 | 1件のコメント | WhatsAppで共有
  • Firefox のHTTPトラフィックの約20%が HTTP/3 を使用しており、これは QUIC および UDP 上で動作する
  • 既存のネットワークI/O層である NSPRRustベースの quinn-udp に置き換えることで、性能とメモリ安全性 を強化
  • 各OSごとに最新のシステムコール(multi-message、segmentation offloading など)を積極的に活用し、性能最適化を適用
  • Windows および macOS では一部機能が互換性やドライバーの問題などで制限されたが、Linux では最適な性能を確認
  • QUIC ECNサポートとUDP I/O に関するさまざまなプラットフォーム別の試行錯誤やバグ修正の経験が、今後のプロジェクトやオープンソースエコシステム にも役立つ見込み

動機

  • Firefox のHTTPトラフィックの約20%が HTTP/3 を使用しており、これは QUIC を通じて動作し、さらに UDP 上に実装されている
  • Firefox は歴史的にネットワークI/Oに NSPR ライブラリを使用してきたが、UDP I/O関連機能は 古く制限が多い(主要な関数は PR_SendToPR_RecvFrom
  • OS は近年、マルチメッセージシステムコール(例: sendmmsgrecvmmsg)や セグメンテーションオフロード(GSO、GRO)といったネットワーク最適化を提供している
  • これらの技術は UDP I/O の性能を大幅に向上させられる
  • Firefox が 既存のUDP I/Oスタックをモダンなシステムコールに置き換えて こうした利点を得られるかを模索

概要

  • プロジェクトは2024年半ばに開始され、目標は Firefox の QUIC UDP I/Oスタックを、サポート対象のすべてのOSでモダンなシステムコールにより再構築 すること
  • 性能改善に加えて、UDP I/Oに メモリ安全性が保証されたRust を活用し、セキュリティ向上も図る
  • QUIC自体はすでにRustで実装されているため、Rustベースの quinn-udp ライブラリ 上で開発を進めた
  • OS間のシステムコール差異は開発難度を高めたが、quinn-udp により開発速度は大きく改善
  • 2025年半ば時点で大半のFirefoxユーザーへの適用が進行中で、性能ベンチマークでは 最大4Gbit/sへ大幅に向上 する結果を示した

UDP I/O構造とモダンな最適化方式

単一データグラム送信

  • 従来方式は sendtorecvfrom を使用し、一度に 単一のUDPデータグラム のみ送受信
  • ユーザー空間とカーネル空間の切り替えコストはデータグラム単位で発生するため、大容量トラフィック環境では 非効率
  • 例: 1500バイト未満のパケットを毎秒数百Mbit以上で送るにはかなりのオーバーヘッドが発生

複数データグラムのバッチ送信

  • Linux など一部のOS では sendmmsg および recvmmsg のようなマルチメッセージシステムコールをサポート
  • 複数のデータグラムを一度に送受信することで、オーバーヘッドを大幅に削減可能

単一の大容量セグメント化データグラム

  • GSO(送信)GRO(受信) などのオフロード技術により、大きなUDPデータグラムをOSまたはNICで自動的に分割 して送信
  • ネットワークインターフェースがパケット単位の分離、チェックサム計算、ヘッダー付与を処理
  • これによりアプリケーション側は たった1回のシステムコールで多数の実パケットを処理可能
  • GSO有効時は Wireshark など一部のネットワークツールでパケット解析のサポートが不十分

Firefox の NSPR 置き換えプロセス

  • まず 単一データグラム送受信 構造で quinn-udp により NSPR を置き換え
  • QUIC実装のデータグラム処理パイプラインを バッチ送受信およびセグメンテーション対応 にリファクタリング
  • multi-message コール、segmentation offload コールをいずれも状況に応じて活用
  • プラットフォーム別の例外処理や各種I/O改善機能を追加

プラットフォーム別の詳細

Windows

  • Windows は WSASendMsg / WSARecvMsg を提供し、従来のMTUサイズのデータグラムまたは大型のセグメント化データグラムをサポート
  • Linux の GSO / GRO に対応する Windows の USO(送信) / URO(受信)
  • 当初は単一データグラムコールのみを使っていて問題なかったが、URO有効時に特定環境(例: Windows on ARM + WSL)で QUICパケット長を判定できない ためページ読み込みが失敗するバグが発生
  • USO / 送信も使用したが、Firefox の Windows インストール環境で パケット損失の増加やネットワークドライバーのクラッシュ などの副作用が見つかった
  • 現在の Firefox では URO / USO を無効化した状態 を維持し、追加のデバッグを進めている

macOS

  • macOS では既存の sendto / recvfrom の代わりに sendmsg / recvmsg を用いて quinn-udp を導入
  • セグメンテーションオフロード機能は有効化されていない
  • 代わりに公式には文書化されていない sendmsg_x / recvmsg_x により バッチ送信 をサポートし、quinn-udp に非公式に適用
  • Apple が将来的にこれらの呼び出しを削除する可能性があるため、デフォルト有効化はせずテストのみ実施 し、実際のリリースには含めなかった

Linux

  • sendmmsg / recvmmsg および GSO / GRO の両方をサポートし、quinn-udp は送信時に GSO をデフォルトで優先
  • Firefox は 接続ごとに個別のUDPソケットを使用 してプライバシー強化を図る(4-tuple 区別)
  • この構造では セグメンテーションオフロードの利点が最大化 され、sendmmsg / recvmmsg のクロス送信の利点は限定的
  • ネットワークサンドボックスや実行時の GSO サポート確認などの小規模な変更を除き、大きな困難なく導入に成功

Android

  • Android は Linux と異なり、システムコール処理経路やセキュリティフィルター(例: seccomp)が異なる
  • x86ベースの Android 5 など 非常に古いプラットフォームのサポートsocketcall の回避、エラー処理など、さまざまな互換性問題が存在
  • 一部環境では ECN ビットを有効にした送信呼び出し時にエラー(EINVAL)が発生し、quinn-udp で 再試行およびオプション無効化戦略 を適用
  • Quinn コミュニティでのさまざまな改善の恩恵により、Firefox も自動的に改善効果を享受 できる

ECN(明示的輻輳通知)サポート

  • モダンなシステムコール導入により ancillary data(付加データ)の送受信をサポートし、QUIC ECN をサポート可能に
  • 小規模なバグはあったが、Firefox Nightly では 半数以上の QUIC 接続が ECN outbound 経路で動作
  • L4S などの新技術が注目されるにつれ、ECNサポートの重要性と活用度が上昇

結論の要約

  • Firefox の QUIC UDP I/O層を quinn-udp ベースの Rust 実装 に置き換え、性能と安全性を同時に確保
  • 古いシステムコールではなく 各OSごとの最新I/Oシステムコール を活用することで、スループット向上と ECN サポートが可能に
  • Windows など一部の最適化機能は互換性問題のため追加改善が必要
  • QUIC の利用率が継続的に増えるにつれ、今後も OS / ドライバーレベルのサポートは発展し続ける見込み

1件のコメント

 
GN⁺ 2025-09-28
Hacker Newsの意見
  • 記事の核心は途中に隠れている

    極端なケースでは、CPUバウンドなベンチマークで < 1Gbit/s から 4 Gbit/s へ改善した。CPU flamegraphでは、ほとんどの時間がI/Oシステムコールと暗号化コードで消費されていた
    ネットワークスループットが400%向上したというのは、UDPネットワークトラフィックにおけるCPU使用量が大幅に減ったことを意味する
    これは特にモバイルやノートPCなどの携帯型クライアントにおいて、電力効率の向上という点でも印象的だ
    こうした移行は常によいものとして受け取られがちだが、この記事は実データでそれを証明していて新鮮に感じる

    • いつか、ユーザー空間とシステムプログラム間でコンテキストをまたぐメッセージパッシングがハードウェアアクセラレーションで動く日が来るのだろうか
  • ここでの改善は実際、超高速(100Gb/s以上)を実現するには必須ではあるが、4Gb/sは正直それほど速くない
    500MB/sなので、これはどこかに深刻に遅いボトルネックがあることを意味する
    カーネルのコンテキストスイッチが1us台とのことだが、実際システムコールとしては高い方だ
    ただし、1パケットあたり平均約500バイトしかなくても500MB/s、つまり4Gb/sは達成できる
    以前の1Gb/sはパケットサイズがもっと小さかったときの話で、UDPパケットを単にNICバッファに押し込むだけなら、メモリコピー速度でも十分可能な水準だ
    暗号化が遅いと言っても、実際にはそうではない
    例えばIntel i5-6500は1729MB/sのAES-128 GCM速度を出したことがある
    今のCPUならコアあたり3-5GB/s、つまり25-40Gb/sも可能で、ここで言われている4Gb/sは低すぎる数値だ
    (AES-128 GCM性能の参考リンク)

    • システムコール待ち時間が高いと言っていたが、その原因はSpectreとMeltdown対策かもしれない
      TCPにはパスバインディングがあるが、UDPにはないため、経路設定に違いが大きい
      暗号化が遅いというのは、小さなPDU(プロトコルデータユニット)ではその通りだ
      大半は大容量TCPフレーム基準で最適化やベンチマークが行われているため、実際には小さいパケットで状態設定コストが目立つ
      tight loopでマイクロベンチマークを回せば数値はよく出るが、実際のランダム性のある環境ではキャッシュ活用効率も下がり、1KB以下のパケットでは効率が大きく落ちる
      さらに追加のフレーミングオーバーヘッドや、帯域外データの妥当性検証などもかなり高コストで動作する
      UDPバッファメモリもデフォルト値が不足していて、実運用では問題が多い
      TCPでは運用しながらバッファサイズを増やし続けてきたが、UDPは90〜00年代の保守的な値にとどまっている
      本当に必要なAPIは、fdをforkしてconnect(2)とルートバインディングを完全にサポートし、その後はsubmission queueベース(uringrioなど)であるべきだ
      暗号化の面では、KDFアプローチが状態コストを大きく減らせる
      PSP方式は一部ベンダーは認めているが、IETFなどではかなり拒否されており、広く普及していない
      ベンダーによる大規模同時実行テストでは、既存のTLS系よりはるかに高いスケーリング値が出ている

    • ベンチマークしたCPUがどのクラスなのかはまったく言及されていない
      そして暗号化オーバーヘッドはQUICプロトコル自体の処理コストだ
      QUICは暗号化オフロード(ハードウェア処理)がTCPに比べて弱く、TCPはkTLSオフロードである程度NIC側で処理できる

  • こういう技術コンテンツは本当に満足度が高かった
    Mozillaのすべての技術資料が、こうして実務エンジニアがきちんと書いた深い内容だったらいいのにと思う
    楽観論(alegria)みたいなもの抜きで、読む価値が高い

  • なぜAndroid 5をいまだにサポートしているのか分からない
    リリースから10年以上経っているし、その端末を使っているユーザーはさらにレガシーだ
    今どきのWebは重すぎて、こういう古い端末ではまともにブラウジングすることすら難しいはずなのに、わざわざ対応する理由が気になる
    たぶん昔のOnePlusのような端末を修理して充電器につないだまま使い、LineageOSのような定番ROMすら入れずに代替アプリストアでFirefoxを使ってみるハッカーくらいだろう
    現実的には、全体の開発速度を遅らせるコストになっている

  • イシュー報告者(同じくMozilla社員)と何度もやり取りした末、問題再現のためにノートPCまで同じモデル、同じ色で買ってテストしたというくだり
    ネットワーク再現の狂った現実を、XKCD 2259 のように見せていて面白かった
    (xkcdの漫画リンク)

    • "The map download struggle" というFactorio開発ブログにもこれに関連する興味深いエピソードがあるのでおすすめ
      (関連ブログ記事)

    • 実際にネットワーク問題を扱ったことがある人なら、mystery packet runtsのせいでより共感できる内容だ
      ほとんどのネットワーク機器はこうしたパケットの処理がうまくない
      UDPやQUICベースのトラフィックは、ある程度以上の大規模クラウド環境でなければ簡単に攻撃に振り回される
      このため、小規模または自前運用のホスティング事業者はますます運営が難しくなり、大規模トラフィック処理能力のあるところだけが残る
      そのため多くのLAN環境では、UDPトラフィックの大半をドロップし、必要な部分だけをレート制限つきで処理している

  • Mozillaバグトラッカー
    macOSとFedoraで、CloudflareがホストしているサイトにFirefoxでアクセスすると、いまだに同じ現象が発生している

  • WindowsとMacOSにもGSO/GRO(大容量ネットワークパケット処理)に似た機能があることを今回初めて知った
    ただ、実際にはバグが多いらしく残念だ

    • MicrosoftとAppleがなぜ自社のネットワークスタックの品質にもっと気を配らないのか疑問だ
      GSO/GROだけにバグがあるわけではないだろうという気もする
  • UDP GSO/GROが構造的にどう動くのか説明できる人はいるか、という質問だ
    UDPは順序のないパケットなのに、QUICの1パケットが複数のUDPパケットに分割されるとき、ヘッダーにシーケンス情報もないのに受信側がどうやって順序を合わせて結合するのか気になる

    • 自分の理解では、アプリケーションレベルではGROが有効でも、実際には結合済みのUDPデータグラムを受け取ることはない
      カーネルが複数のデータグラムを1つの構造体に入れ、各層の間で境界(たとえば sk_buff 内のdata fragments)を維持したまま渡すという考え方だ
      正確な専門家ではないが、この仕組みがどう動くのか調べる中でこの記事を参考にした
  • 「私たちはQuinnプロジェクトのUDP I/Oライブラリであるquinn-udpの上で開発を始め、それによって開発速度が大きく上がった」と書かれていたが
    それならQuinnプロジェクトに支援を行ったのだろうかと気になる
    (Quinn支援リンク)

    • 資金支援について直接聞いてみたところ、MozillaのSenior Principal Software Engineerが「Mozillaにはお金がないんです」と答えてくれた
      ただしコードはものすごくたくさん貢献してくれていて、本当に感謝している
      (私はQuinnのメンテナーだ)

    • 「支援したのか?」という質問に対して、Mozillaはオープンソース支援をするよりもCEOの報酬にさらに数百万ドル使うのが流儀だ、という意見も出ていた
      フラッグシップ製品(Firefox)さえ崩れかけているのに、という文脈だ

    • コードなど、ほかの形でどんな貢献があったのか気になる

  • sendmmsg/recvmmsg が「最新」と呼ばれているのは驚きだ
    実際にはかなり長い間存在してきたシステムコールだ
    Linuxの話題ならio_uringにも触れられるかと思ったが、なくて残念だった

    • io_uringには複数のUDPダイアグラムを一度に処理する、本当の意味でのバッチ機能はない
      せいぜい、sendmsgrecvmsg を複数まとめて要求する程度だ
      GSO/GROこそが答えだ
      sendmmsg/recvmmsg はすでに非常に古い技術で、カーネル開発者の中にはもう廃止したいと思っている人もいる
      (関連GitHub議論)