スパニングツリーの「タイマー」が、あなたのWebサービスのレイテンシを殺している件について
ネットワークエンジニアの端くれであれば、データセンターの端っこやフロアスイッチの裏で、オレンジ色に点滅するポートを見たことがない者はいないだろう。スパニングツリープロトコル(STP)――それはレイ2ループという地獄の釜の蓋を閉め続ける、ネットワークの古き良き守護神だ。
だが、この守護神、デフォルト設定のまま放置していないだろうか?
「とりあえずCiscoのデフォルトで動いているから安心」「トポロジ変更なんて滅多に起きないし」などと高をくくっているとしたら、それは現代のハイパースケールなインフラ要件に対して、あまりにも無頓着すぎると言わざるを得ない。デフォルトのSTPタイマーが生み出す「沈黙の数十秒間」は、上位レイヤーで稼働するTCPの再送制御、TLSハンドシェイク、そしてアプリケーション層の死活監視において、致命的なレイテンシのスパイクやタイムアウトを引き起こす引き金になり得るのだ。
今回は、STPの根幹を成す3つのタイマー(Hello Timer、Max Age、Forward Delay)の内部挙動をパケットレベルで解剖し、現代の高速ネットワークにおいてこれらがどう影響するのか、そして我々インフラアーキテクトがどう手懐けるべきかをディープに解説しよう。
—
STPタイマーの三位一体:デフォルト値が抱える「歴史的負債」
まずは基本のおさらいから始めよう。IEEE 802.1Dで規定された古典的なSTP(あるいはPVST+などの拡張)において、トポロジの収束を支配する主要なタイマーは以下の3つだ。
1. Hello Timer(デフォルト: 2秒)
ルートブリッジが定期的にBPDU(Bridge Protocol Data Unit)を生成し、トポロジの健常性をブロードキャストする間隔。
2. Max Age(デフォルト: 20秒)
スイッチが最後にルートBPDUを受信してから、「ルートへのパスが消滅した」とみなすまでの保持時間(エージングタイム)。
3. Forward Delay(デフォルト: 15秒)
ポートがリスニング(Listening)状態およびラーニング(Learning)状態のそれぞれに留まる時間。ブロッキング状態からフォワーディング状態に移行するまでに、このタイマーが2回(計30秒)発動する。
障害発生からフォワーディング再開までの「絶望のカウントダウン」
リンクダウンなどのトポロジ変更が発生した瞬間を想像してほしい。バックアップパスへの切り替わりには、以下のプロセスが強制される。
[障害発生]
↓
[Max Age 経過 (最大20秒)] : 「ルートBPDUが来ない!トポロジが変わったはずだ」とスイッチが検知
↓
[Listening 状態 (15秒)] : MACアドレステーブルを学習せず、BPDUの送受信のみ行う
↓
[Learning 状態 (15秒)] : MACアドレステーブルの構築を開始するが、データフレームは転送しない
↓
[Forwarding 状態へ移行] : ようやくトラフィックの転送が再開 (合計で最大 20 + 15 + 15 = 50秒!)
そう、デフォルト設定のままでは、たった1本の物理リンクが断線しただけで、ネットワークは最大50秒間もの間、完全に沈黙するのだ。
—
パケットとレイヤーの連鎖:L2の遅延が上位レイヤーに与える絶望的な影響
「L2が50秒止まるくらい、上位のL3やTCPが何とかしてくれるだろう」――もしそう考えているなら、インフラ設計者としての解像度が少し足りないと言わざるを得ない。この50秒のブラックアウトは、現代のWebアプリケーションスタックにおいて以下のようなドミノ倒しを引き起こす。
1. TCPコネクションの強制切断とハンドシェイクの破綻
STPの収束中にクライアントからサーバーへのリクエスト(あるいはその逆)が発生すると、SYNパケットはブラックホールに消える。
Linuxカーネルのデフォルト設定(tcp_retries2 = 15 など)では、最初のSYNロスに対して数秒おきに再送を行いつつ、最終的に15分近く粘る挙動を示すが、ロードバランサーやプロキシ(Nginx, Envoyなど)のタイムアウト設定は通常もっとシビアだ。数秒〜数十秒のL2断は、確立済みのTCPコネクションのキープアライブ(Keep-Alive)を即座に失敗させ、接続を容赦なく切断する。
2. TLSハンドシェイクの再試行とレイテンシのスパイク
APIのマイクロサービス間通信や、クライアントとエッジ間の通信において、TLS 1.3の0-RTTや1-RTTハンドシェイクの最中にL2のトポロジ変更が直撃したとしよう。セッションチケットのやり取りやCertificateの検証パケットがロストした場合、クライアント側のTLSライブラリはタイムアウトまでブロックされ、ユーザーエクスペリエンス(UX)に直接的な致命傷を与える。
—
チューニングの実践:IEEE 802.1W (RSTP) への移行とタイマー短縮の限界
現代のインフラストラクチャにおいて、古典的な802.1Dをそのまま使用する理由はもはや存在しない。Cisco CatalystやNexus、あるいはLinuxベースのブリッジ(bridge ユーティリティ)を用いる場合でも、基本的にはIEEE 802.1W(Rapid Spanning Tree Protocol: RSTP)をベースに設計すべきだ。
RSTPでは、従来のタイマー依存型のステート遷移を廃し、「プロポーザル/アグリメント(Proposal/Agreement)」というハンドシェイクメカニズムを採用している。これにより、ポイント・トゥ・ポイントのリンクであれば、収束時間は数秒からミリ秒単位(数回のエラー検出程度)へと劇的に短縮される。
しかし、レガシー機器の混在や、どうしてもSTP(PVST+など)を使わざるを得ない環境のために、タイマーを直接チューニングする手法についても知っておく必要がある。
危険な領域:タイマーをむやみに短縮することの弊害
「じゃあ、Helloを1秒、Max Ageを6秒、Forward Delayを4秒にすれば最速で収束するはずだ!」――短絡的なエンジニアはこう考える。しかし、ここに大きな罠がある。
STPのタイマーを極端に短くすると、「ネットワークの遅延や微小なパケットロスを、誤ってトポロジの障害(ループの発生)と誤認する」という最悪の副作用が生じる。
- 輻輳(Congestion)によってたまたまHelloパケットが2秒遅延しただけで、対向スイッチが「ルートが死んだ」と勘違いし、不必要なトポロジ変更(TCN: Topology Change Notification)を引き起こす。
- TCNが走ると、スイッチは既存のMACアドレステーブルをフラッシュ(エージングタイムを強制的に15秒に短縮)するため、ネットワーク全体で一時的なフラッディング(ユニキャストフラッドの嵐)が発生し、さらなる輻輳を招くというデススパイラルに陥る。
安全かつ効果的なチューニングの指針(Cisco IOSの例)
もしレガシーなSTP環境で収束を高速化したい場合、Cisco環境では「Diameter(ネットワークの直径:ルートから最も離れたスイッチまでのホップ数)」を考慮したブリッジ保証(bridge-assurance)や、パスコストの最適化と併せて、タイマーを少しだけ保守的に短縮するアプローチをとる。
! ルートブリッジのプライオリティを確実に固定し、不安定なトポロジ変更を防ぐ
spanning-vlan 10 root primary
! Hello Timerを短縮する場合(デフォルト2秒から1秒へ。ただし設計上の慎重な検証が必要)
spanning-tree vlan 10 hello-time 1
! Forward Delayの短縮(最小8秒まで設定可能だが、デフォルト15秒からの短縮はL2の安定性とトレードオフ)
spanning-tree vlan 10 forward-time 10
! Max Ageの短縮(最小6秒、最大40秒。通常はHelloの3倍以上を維持)
spanning-tree vlan 10 max-age 16
※実務上の鉄則として、タイマーの直接変更を行うよりも、RSTP(spanning-tree mode rapid-pvst)への移行、あるいはリンクステートプロトコル(OSPFやBGP)を用いたL3ルーティングデザインへの転換を最優先で検討すべきである。L2のスパニングツリーに依存する設計自体が、クラウドネイティブおよびハイパフォーマンスな現代のインフラにおいてはレガシーな負債となりやすい。
—
Linuxカーネルにおけるブリッジ(L2)のタイマー制御
ベアメタルサーバーやKVMによる仮想化基盤(Linuxブリッジ)でL2フォワーディングを行っている場合も、カーネルのブリッジモジュールがSTPをサポートしている。
デフォルトではLinuxブリッジのSTPは無効化されているか、あるいは保守的なタイマーで動作している。iproute2 スイートを使用してこれらを制御する際の設定例を確認しておこう。
# 仮想ブリッジインタフェース 'br0' を作成
sudo ip link add name br0 type bridge
# STPを有効化 (0: 無効, 1: 有効)
sudo ip link set br0 type bridge stp_state 1
# Hello Timeをセンチ秒単位で設定 (例: 1秒 = 100centisec)
sudo ip link set br0 type bridge hello_time 100
# Forward Delayをセンチ秒単位で設定 (例: 4秒 = 400centisec)
sudo ip link set br0 type bridge forward_delay 400
# Max Ageをセンチ秒単位で設定 (例: 12秒 = 1200centisec)
sudo ip link set br0 type bridge max_age 1200
# インタフェースを有効化
sudo ip link set br0 up
Linux環境においてコンテナ(Dockerなど)のネットワークや仮想マシン(VM)のブリッジを構築する際、冗長化構成をとるならば、LinuxブリッジのSTPチューニングに頼るのではなく、LACP(IEEE 802.3ad)によるリンクアグリゲーションと、L3ルーティング(BGP unnumbered等)の組み合わせによって、スパニングツリーそのものを排除するアーキテクチャこそが、現代のインフラエンジニアリングにおける「正解」である。
—
結びにかえて:パケットの挙動を愛せ
ネットワークのトラブルシューティングにおいて、最も恐ろしいのは「なぜ動いているのか分からないが、動いている」という状態のまま放置されたブラックボックスだ。STPのタイマーもその一つである。
「たかがタイマーの数秒」と侮るなかれ。その数秒の背後には、BPDUの送受信ロジックがあり、ステートマシンの厳密な遷移があり、そして何より、その上を流れる数千・数万のTCPコネクションの命運がかかっている。
プロトコルの仕様書をめくり、パケットキャプチャのタイムスタンプを睨みつけ、カーネルのソースコードやハードウェアのASICの挙動に思いを馳せる――それこそが、真のインフラアーキテクトの矜持である。あなたのネットワークのタイマーは、本当に最適化されているか? 今一度、スイッチのコンソールにログインし、その設定値と向き合ってみてほしい。
コメント