帯域の「門番」を極める:イーサネット・ポリシングの深淵と実務的設計術
ネットワークエンジニアの諸君、今日もパケットの海を泳いでいるだろうか。
クラウドネイティブな時代になっても、インフラの根幹は変わらない。我々が書くWeb APIがいかに美しくても、その下を支えるイーサネット・リンクが「混雑」という名の暴力に晒されれば、一瞬でレイテンシは跳ね上がり、TCPの再送タイマーが阿鼻叫喚を巻き起こす。
今日は、そんなネットワークの「門番」であるポリシング(Policing)について、現場の泥臭い知見を交えて深掘りしていこう。教科書通りの解説はGoogleに任せて、ここでは「なぜそのトラフィックが捨てられるのか」という物理層に近い視座で語る。
—
1. ポリシングとは「現実との妥協」である
ポリシングを一言で言えば、「契約(プロファイル)を超えたトラフィックに対する、冷徹な制裁」だ。
RFC 2697 (A Two Rate Three Color Marker) や RFC 2698 にある通り、パケットのフローをトークンバケットアルゴリズムで計測し、以下のいずれかの処置を下す。
- Conform(順守): 契約帯域内。そのまま通過させる。
- Exceed(超過): 契約帯域を超えたが、許容範囲内。マーキングして通過させるか、破棄する。
- Violate(違反): 完全に規格外。即座に破棄(Drop)。
これらは単なるトラフィック制限ではない。Web APIの開発者がしばしば遭遇する「なぜか一部のリクエストだけがタイムアウトする」「パケットロスが発生しているのにインターフェース統計にはエラーが出ない」という怪奇現象の正体は、大抵このポリシングによる破棄だ。
—
2. トークンバケットの仕組み:バケツの深さを理解する
ポリシングの挙動を理解する鍵は、CIR(Committed Information Rate)とBc(Committed Burst Size)の二つにある。
- CIR: 許可される平均帯域。これがネットワークの「公約」だ。
- Bc: バースト許容量。短い間にどれだけ「一気に」流せるか。
例えば、CIRを10Mbpsに設定しても、Bcが小さすぎると、TCPの最初のスロースタートで発生する数パケットのバーストさえ「超過」とみなされ、即座に破棄される。結果、TCPの窓サイズは小さくなり、スループットは理論値の半分も出なくなる。これが「帯域制限を入れたらなぜかパフォーマンスが劇的に落ちた」という現場あるあるの真相だ。
—
3. 実践:Cisco IOSにおけるポリシング設定
実務でよく使う class-map と policy-map を使った設定例を見せよう。ここでは、Web API(80番ポート)宛のトラフィックを100Mbpsに制限し、超過分は DSCP 値を AF11 から AF13 に書き換えて(Remarking)「優先度を下げて」流す設定だ。
! クラスマップで対象のトラフィックを定義
class-map match-any WEB-TRAFFIC
match protocol http
match protocol https
! ポリシーマップでアクションを定義
policy-map POLICE-WEB-TRAFFIC
class WEB-TRAFFIC
! 100Mbpsまで許可。超過分はマーキングして通過させる
police 100000000 conform-action transmit exceed-action set-dscp-transmit af13 violate-action drop
この設定の肝は、violate-action drop だ。もしここで exceed-action を適当に設定すると、アップストリームのL3スイッチやルータで「順序逆転(Out-of-order)」が発生し、TCPの再送制御が狂う可能性がある。ポリシングは常に「下流への影響」を考慮して設計しなければならない。
—
4. アプリケーション視点での観測とデバッグ
インフラ側でポリシングを適用している最中、開発者側から「APIのレスポンスが不安定だ」と言われたら、まずは curl を使ってパケットのロス状況を疑うべきだ。
# -w オプションで統計情報を取得し、トータル転送量と平均速度を可視化する
curl -w "Speed: %{speed_download} bytes/sec\n" -o /dev/null http://api.example.com/data
また、PythonでAPIクライアントを書いているなら、リクエストヘッダーに X-Trace-ID を仕込み、ルータ側で access-list を使って当該パケットがポリサーにヒットしているかカウントを確認するのが、最も確実なデバッグ手法だ。
import requests
# 擬似的なトラフィック生成スクリプト
def send_requests(url, count):
for i in range(count):
# 意図的にバーストさせる
try:
r = requests.get(url, timeout=2)
print(f"Status: {r.status_code}")
except requests.exceptions.Timeout:
# ここでタイムアウトが頻発するなら、ポリサーのBc設定を見直す必要がある
print("Request Timed Out - Check Policing logs!")
send_requests("http://api.example.com/data", 100)
—
終わりに:エンジニアとしての心得
ポリシングは魔法ではない。単なる「パケットの間引き」だ。
帯域制限をかける際、最も重要なのは「どのパケットを優先し、どのパケットを捨てるか」というビジネスロジックとネットワークの整合性を合わせることにある。
- ログを信じるな、パケットを見ろ(
tcpdumpやwiresharkでの確認は必須) - バーストサイズ(Bc)は余裕を持て(TCPの挙動を殺すな)
- マーキング(Remarking)後の扱いを疎かにするな(下流のQoS設定と整合しているか?)
ネットワークの深淵を覗くとき、そこには必ず「論理」と「物理」のせめぎ合いがある。次に誰かが「ネットが遅い」と言ってきたら、まずはそのパケットがどのバケットに放り込まれているかを想像してほしい。
それこそが、真のインフラアーキテクトへの第一歩だ。健闘を祈る。
コメント