TL

パケットスケジューリング:WFQ・DRR・HTB の原理

なぜ重み付き公平を「仮想時刻」で実現できるのかが腑に落ちる。WFQ の仮想終了時刻、DRR が O(1) でそれを近似する仕組み、HTB の階層帯域配分を数理から解説。

応用パケットスケジューリングWFQDRRHTBQoS最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.WFQ は各パケットに仮想終了時刻を割り当て、その昇順で送ることで重み比どおりの帯域配分を近似する。仮想時刻計算が O(N) でコスト高。
  • 2.DRR はキューごとに quantum と deficit カウンタを持ち、ラウンドロビンで回るだけで重み付き公平を 1 パケットあたり O(1) で近似する。
  • 3.HTB はトークンバケットを木構造に組み、子の超過分を親の余剰から借りる(borrow)ことで、最低保証と上限と余剰の再配分を同時に満たす。

公平キューイングが解く問題

リンクが混雑したとき、複数のフロー(あるいはトラフィッククラス)にどんな比率で帯域を割り当てるか。これがパケットスケジューラの仕事です。素朴な FIFO(テールドロップ)では、攻撃的に送るフローほど多くのキューを占有し、帯域を奪います。QoS(通信品質の制御) の「スケジューリング」段にあたる部分を、原理から厳密に詰めるのがこの記事です。

理想は GPS(Generalized Processor Sharing) という流体モデルです。GPS は各フロー i に重み w_i を与え、バックログのある(送るものがある)フローの間で、リンク容量を重み比で無限に細かく分配します。あるフローのバックログが切れれば、その帯域は残りのフローへ重み比で即座に再配分される。問題は、現実のパケットは分割できず、1 個ずつ逐次に送るしかない点です。GPS をパケット単位でどう近似するかが、WFQ・DRR・HTB の分かれ道になります。

WFQ — 仮想終了時刻による近似

WFQ(Weighted Fair Queueing)の発想は、「GPS の世界でこのパケットがいつ送り終わるか」を計算し、その仮想終了時刻(virtual finish time)が早い順に実際のパケットを送る、というものです。鍵は実時間ではなく仮想時間 V(t) を使うことです。

仮想時間はリンクの混雑度に応じて進む速さが変わる時計です。バックログ中のフローの重み総和を Σw とすると、V(t) は実時間あたり C / Σw の速さで進みます(C はリンク容量)。アクティブなフローが少ないほど V は速く進む、という性質がポイントです。各パケット k(フロー i、長さ L)に対し、開始タグ S と終了タグ F を次のように割り当てます。

# パケット到着時のタグ付け(フロー i、長さ L)
S = max(V(now), F_prev_i)     # 直前パケットの終了タグか、現在の仮想時刻の遅い方
F = S + L / w_i               # 仮想時間での所要量。重みが大きいほど F は小さく進む
# 送出は F が最小のパケットから

L / w_i が核心です。重み w_i が大きいフローほど、同じ長さでも F の増分が小さい。つまり仮想時間軸での「進みが遅く」見え、より頻繁に最小 F として選ばれ、結果として帯域を多く得ます。max をとるのは、フローがアイドルから復帰したとき、過去に溜めた「貸し」で帯域を独占させないためです。WFQ はこのタグ順送出により、GPS との遅延差が最大 1 パケット長に収まることが保証されます(厳密な公平性)。

なぜ仮想時間が必要か

実時間で「終了時刻」を計算しようとすると、他フローのバックログが切れるたびに自分の送出レートが上がり、終了時刻が前倒しになります。すべてのパケットの予定を再計算しなければならず破綻します。仮想時間 V は混雑度に連動して進むため、F = S + L / w_i というタグはアクティブ集合が変わっても再計算不要で、相対順序が保たれます。これが WFQ の数学的な巧妙さです。

WFQ の弱点は計算量です。V(t) の更新はアクティブフロー数に依存し、各送出で最小 F を選ぶのに優先度キュー(ソート)が要ります。1 パケットあたり最悪 O(log N)、V の正確な追従まで含めると実装が重く、高速リンクのハードウェアでは扱いにくい。ここで O(1) 近似の DRR が登場します。

DRR — Deficit Round Robin の O(1) 近似

DRR(Deficit Round Robin)は仮想時刻計算を完全に捨て、ラウンドロビン+積み立てだけで重み付き公平を近似します。各キュー i に二つの値を持たせます。

  • quantum_i(量子): 1 巡で送ってよいバイト数の基準。重み比に比例させる(quantum_i = w_i × base)。
  • deficit_i(赤字カウンタ): 前の巡で「送りたかったのに送れなかった分」の繰り越し。

スケジューラはアクティブキューを順に回り、各キューで deficitquantum を足し、先頭パケットの長さが deficit 以下なら送って deficit から引く、を繰り返します。先頭パケットが大きすぎて送れなければ、deficit残したまま次のキューへ回ります。残った deficit は次の巡に繰り越されるので、いつか必ず送れます。

# DRR の 1 巡(アクティブキューのリストを順に処理)
for each active queue i:
    deficit_i += quantum_i
    while queue_i not empty and head(queue_i).len <= deficit_i:
        pkt = dequeue(queue_i)
        deficit_i -= pkt.len
        send(pkt)
    if queue_i empty:
        deficit_i = 0          # 空になったら貸しをリセット(独占防止)

繰り越し(deficit)こそが公平性の源泉です。可変長パケットでも、各キューが 1 巡で実際に送れるバイト数は長期的に quantum_i へ収束し、配分比は quantum 比=重み比に一致します。MTU 未満の端数は次巡へ持ち越されるだけで失われません。

計算量が決定的な利点です。quantum最大パケット長(MTU)以上に選べば、各キューは 1 巡で必ず最低 1 パケットを送れるため、キューを空回りすることがありません。すると 1 パケットの送出にかかる処理は定数回に収まり、1 パケットあたり O(1) が成立します。ソートも仮想時刻更新も不要なので、高速リンクや Ethernet スイッチの内部処理 のようなハードウェア実装に向きます。代償は遅延境界の緩さで、GPS との差は WFQ の「1 パケット長」より大きく、おおむね quantum のオーダーになります。実用上は十分小さく、Linux の FQ-CoDel はこの DRR をフロー分離に採用しています(バッファブロートと AQM 参照)。

観点WFQDRR
近似の手段仮想終了時刻のソートquantum + deficit のラウンドロビン
1パケットの計算量O(log N)(最小Fの選択)O(1)(quantum ≧ MTU のとき)
GPSとの遅延差最大1パケット長(厳密)おおむね quantum のオーダー
可変長パケットL/w_i で自然に扱うdeficit の繰り越しで吸収
実装のしやすさ重い(HW向きでない)軽い(HW実装に好適)

HTB — 階層トークンバケットによる帯域配分

WFQ・DRR がフロー間の公平を扱うのに対し、HTB(Hierarchical Token Bucket)が解くのは別の問題です。「各クラスに最低帯域を保証しつつ、誰かが余らせたら他クラスがそれを借りて使い、ただし上限は超えない」という階層的な配分です。Linux tc の代表的な qdisc で、トラフィックを木構造に組みます。

各クラスは二つのレートを持ちます。rate(保証帯域)と ceil(上限帯域)です。実装はトークンバケットで、rate ぶんのトークンが定期的に補充され、パケット送出でトークンを消費します。HTB の核心は borrow(借用) です。あるクラスが自分の rate を使い切っても ceil に達していなければ、親クラスの余剰トークンを借りて送り続けられます。親に余剰がなければさらにその親へ、と木を上へたどります。

# HTB クラスの送出可否(概念)
自クラスのトークンあり          → green : 自分の rate 内。送る
自クラス枯渇・親に余剰あり       → yellow: borrow して送る(ceil まで)
ceil 到達 / 親もすべて枯渇       → red   : 送れない。整形(待たせる)

この三状態(green/yellow/red)により、HTB は次を同時に満たします。第一に、各クラスは少なくとも自分の rate保証される(親に貸す前に自分が使えるため)。第二に、回線に余剰があれば ceil まで借りて伸びるので帯域を遊ばせない。第三に、ceil上限が効くので特定クラスの暴走を防げる。葉クラスの内側ではさらに DRR などで個々のフローを公平化でき、「クラス間は階層保証、クラス内はフロー公平」という二層構成が組めます。

rate と ceil の使い分け

rate は「最低でもこれだけは確保する」保証、ceil は「混んでいなければここまで使ってよい」上限です。rate = ceil にすると借用が起きず固定帯域のハードリミット(純粋なシェーピング)になります。rate < ceil とすると、平時は ceil まで伸び、輻輳時には少なくとも rate まで縮退する弾力的な配分になります。子の rate の総和は親の rate を超えないよう設計するのが鉄則で、超えると保証が破れます。

保証は親子の rate 整合があってこそ

HTB で「最低帯域を保証したつもりが守られない」典型は、子クラスの rate 合計が親の rate(または実リンク速度)を上回っている設定です。物理的に存在しない帯域は保証できません。保証を成立させるには Σ child.rate ≦ parent.rate ≦ 実効リンク速度 を全階層で満たす必要があります。ceil は重ねて設定してよい(借用で動的に調整される)が、rate の総和だけは厳守してください。

三者の役割分担

同じ「スケジューリング」でも狙いが異なります。WFQ は厳密な公平性と最小遅延境界を、DRR はそれを O(1) で実用化する近似を、HTB は公平ではなく階層的な保証・上限・借用を担います。実務では HTB で帯域の大枠(VoIP に最低保証、バックアップに上限)を切り、その葉で FQ-CoDel/DRR によりフロー間の公平と低遅延を確保する、という組み合わせが定番です。背景の帯域と遅延の関係は 帯域・レイテンシ・スループット を、輻輳制御との役割分担は バッファブロートと AQM を参照してください。

試験・面接で問われる急所

「WFQ と DRR の本質的な違いは何か」に即答できること。答えは「WFQ は仮想終了時刻 F = S + L/w をソートして厳密公平(GPS 差 1 パケット長)を得るが O(log N)。DRR は quantum と deficit のラウンドロビンで同じ重み付き公平を O(1) に近似する(quantum ≧ MTU が条件)」。あわせて、HTB の borrow が「自分の rate を使い切っても ceil 未満なら親の余剰を借りる」三状態制御であること、保証成立には子 rate 総和 ≦ 親 rate が必須であることが頻出です。

ネットワーク Article

パケットスケジューリング:WFQ・DRR・HTB の原理を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

パケットスケジューリング

比較で見る軸

難易度: advanced / カテゴリ: ネットワーク / タグ数: 5

導入後に効く点

DRR はキューごとに quantum と deficit カウンタを持ち、ラウンドロビンで回るだけで重み付き公平を 1 パケットあたり O(1) で近似する。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
ネットワーク
タグ数
5

判断チェックリスト

  • 自社の用途が「パケットスケジューリング / WFQ」に近いか確認する。
  • 強みである「WFQ は各パケットに仮想終了時刻を割り当て、その昇順で送ることで重み比どおりの帯域配分を近似する。仮想時刻計算が O(N) でコスト高。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

パケットスケジューリングWFQDRRHTBQoSパケットスケジューリングWFQDRR
参考: 公式情報