こんにちは。今日もパケットの海を泳いでいますか? ネットワークプロトコルの深淵へようこそ。
「APIのレスポンスが妙に遅い」「特定のバッチ処理が走ると、リアルタイム通信がガタつく」――そんな時、多くのエンジニアはアプリケーションコードやDBのインデックスを疑います。しかし、インフラの深層、特にイーサネットスイッチの「出口(Egress Port)」で何が起きているかに目を向ける人は驚くほど少ない。
今日は、スイッチの内部でパケットたちがどのように列に並び、どのようなアルゴリズムで送り出されているのか。実務で避けては通れない「Strict Priority (SP)」と「Weighted Fair Queuing (WFQ)」という2つの巨頭にスポットを当て、その挙動と使い分けを徹底解説します。
—
1. 出口という名のボトルネック:なぜキューイングが必要か
イーサネットスイッチの仕事は、入ってきたフレームを適切なポートへ転送することです。しかし、複数の入力ポートから特定の1Gbpsポートへ、同時に合計2Gbpsのデータが流れ込もうとしたらどうなるか?
当然、溢れます。この時、スイッチ内部のバッファにパケットが溜まり、送り出される順番を待つ「行列」ができます。これがキューイング(Queuing)です。
ここで何も制御をしなければ、先に来たものが先に処理される単純な「FIFO (First-In, First-Out)」になりますが、これでは「1ミリ秒を争う音声通話(VoIP)」も「急ぎではない巨大なバックアップ」も同じ扱いになってしまいます。これを解決するのが、今回紹介するスケジューリング・アルゴリズムです。
—
2. Strict Priority (SP):絶対王政の優先制御
Strict Priority (SP: 厳格優先キューイング)は、その名の通り「強い者がすべてを優先される」アルゴリズムです。
仕組みと挙動
スイッチの出力ポートに複数のキュー(例:Queue 0〜7)がある場合、SPは「最も番号の大きいキューにパケットがある限り、下のキューからは絶対に送り出さない」という鉄の掟に従います。
- メリット: 優先度の高いパケット(VoIPのRTPや制御信号など)に対して、最小の遅延とジッタを保証できる。
- デメリット: 「Starvation(飢餓状態)」の発生。優先キューに常にパケットが居座り続けると、低い優先度の通信が1ビットも送信されなくなる。
実務での使いどころ
これは「命に関わる通信」や「ネットワークの根幹を支えるプロトコル(BGPやOSPF等)」にのみ限定して割り当てるのがセオリーです。Web APIのトラフィックを安易にこれに入れると、他の通信を完全に殺しかねません。
—
3. Weighted Fair Queuing (WFQ):公平性と重み付けの調和
SPの「弱者切り捨て」を解決するために生まれたのが、Weighted Fair Queuing (WFQ: 重み付きフェアキューイング)です。
仕組みと挙動
WFQは、各キューに「重み(Weight)」を設定し、その比率に応じて帯域を分配します。例えば、Queue 1に「10」、Queue 2に「20」の重みがあれば、1:2の割合でパケットが送り出されます。
- メリット: 低い優先度のキューにも必ず送信機会が回ってくるため、通信が完全に止まることがない。
- デメリット: 高優先度のパケットであっても、他のキューの送信が終わるまでわずかな待ち時間(ジッタ)が発生する可能性がある。
現代のスイッチでは、これをさらに進化させたCBWFQ (Class-Based WFQ)や、SPと組み合わせたLLQ (Low Latency Queuing)が主流です。
—
4. 現場の設定:Ciscoスイッチ(MQC)での実装例
では、実際にインフラエンジニアがどのように設定を投入するか見てみましょう。Ciscoの「Modular QoS CLI (MQC)」を例に、APIトラフィックを「少し優先」しつつ、音声通話を「最優先」する構成を作ります。
! --- Class Map: トラフィックを分類する ---
class-map match-any VOICE_TRAFFIC
match dscp ef ! 音声パケット(DSCP 46)をマッチング
class-map match-any API_TRAFFIC
match dscp af31 ! APIパケット(DSCP 26)をマッチング
! --- Policy Map: キューイング方式を定義する ---
policy-map QOS_POLICY_OUT
class VOICE_TRAFFIC
priority percent 10 ! Strict Priority (LLQ) として10%の帯域を予約し、最優先
class API_TRAFFIC
bandwidth remaining percent 60 ! 残りの帯域の60%をWFQ的に割り当て
class class-default
bandwidth remaining percent 40 ! その他すべての通信に40%を割り当て(飢餓防止)
! --- Interface: 物理ポートに適用する ---
interface GigabitEthernet1/0/1
service-policy output QOS_POLICY_OUT
ここでは、priorityコマンドがStrict Priorityを意味し、bandwidthコマンドがWFQ的な帯域保証を意味しています。この組み合わせこそが、現代のエンタープライズネットワークの黄金律です。
—
5. アプリケーション層からの観測:Pythonによる遅延シミュレーション
インフラ側でQoS(Quality of Service)を設定しても、アプリケーション側でそれが効いているかを検証しなければ意味がありません。
以下のPythonコードは、HTTPリクエストのレスポンスタイムを計測し、ネットワークの輻輳時に優先制御が機能しているかを簡易的にチェックするためのスケルトンです。
import requests
import time
# 検証対象のAPIエンドポイント
API_URL = "https://api.example.com/v1/data"
def check_latency(priority_label):
"""
APIのレスポンスタイムを計測する
"""
headers = {
# 本来、DSCP値はIPヘッダに書き込むものだが、
# アプリ側で識別子を付与し、上位のルータでマークし直す運用も多い
"X-Priority-Tag": priority_label,
"User-Agent": "QoS-Checker-v1.0"
}
start_time = time.perf_counter()
try:
# ネットワークの輻輳を想定し、タイムアウトを設定
response = requests.get(API_URL, headers=headers, timeout=5)
end_time = time.perf_counter()
latency = (end_time - start_time) * 1000
print(f"[{priority_label}] Status: {response.status_code}, Latency: {latency:.2f} ms")
except requests.exceptions.RequestException as e:
print(f"[{priority_label}] Error: {e}")
if __name__ == "__main__":
# 複数回実行して、輻輳時の挙動(ジッタ)を確認する
for i in range(5):
check_latency("High-Priority-API")
time.sleep(0.5)
もしスイッチでWFQやSPが正しく設定されていれば、バックグラウンドで巨大なファイル転送(scpやrsyncなど)を走らせたとしても、このスクリプトのLatencyは安定した数値を叩き出すはずです。逆に設定がなければ、レイテンシは数百ミリ秒まで跳ね上がるでしょう。
—
6. まとめ:シニアエンジニアからの助言
「パケットは等しく扱うべきだ」という理想論は、限られた帯域という物理的な現実の前では通用しません。
1. Strict Priorityは、絶対に遅延が許されない少量かつ重要なパケット(音声、制御系)に。ただし、使いすぎると他の通信を殺す。
2. WFQは、業務アプリケーションやAPIトラフィックに。帯域を「分け合う」ことで、システム全体の安定性を保つ。
私たちが書くコードの一行一行、そして叩くAPIの裏側には、必ずこうした「キューイングの戦場」が存在します。トラブルシューティングの際、Wiresharkでパケットを見るだけでなく、スイッチの show interface priority-queue のようなコマンドで、ドロップが発生していないか確認できるエンジニアになってください。
パケットの気持ちを理解すれば、インフラはもっと面白くなります。それでは、また次のレイヤでお会いしましょう。
コメント