よくある光景:1つのプロセスが帯域を「独占」する
サーバーが順調に稼働していると思いきや、突然 Web サービスがタイムアウト。調査の結果、クラウドへのデータバックアップスクリプトが帯域の 95% を占有していることが判明しました。顧客はアクセスできず、あなたは焦ってプロセスを停止する方法を探す。そんな時、tc (Traffic Control) が救世主となります。
多くのシステムエンジニアは、その構文が「暗号」のように見えるため、tc を敬遠しがちです。しかし、蛇口とバケツの原理さえ理解すれば、このツールは非常に論理的です。筆者もかつて、一部のユーザーがダウンロードツールを使用して全帯域を圧迫し、他のユーザーがストリーミングできなくなった際、tc を使ってシステムを救ったことがあります。
クイックソリューション:30秒でネットワーク速度を 1Mbps に制限する
ネットワークカード eth0 の帯域を今すぐ制限する必要がありますか? tbf (Token Bucket Filter) を使いましょう。これは CPU に負荷をかけずに速度を制限する最もシンプルなアルゴリズムです。
1. ネットワークカードの確認
ip link show
処理対象のインターフェースを eth0 と仮定します。
2. 帯域制限コマンドの適用
# 1mbit に制限、バースト 32kbit、最大レイテンシ 400ms
sudo tc qdisc add dev eth0 root tbf rate 1mbit burst 32kbit latency 400ms
3. 設定の確認
tc -s qdisc show dev eth0
wget でファイルをダウンロードしてみてください。速度が正確に ~125 KB/s(1Mbps 相当)に制限されていることがわかります。1バイトも超過しません。
4. 作業完了後の設定削除
sudo tc qdisc del dev eth0 root
仕組みの解剖:Qdisc、Class、Filter
より詳細なカスタマイズを行うには、以下の3つの柱を理解する必要があります:
- Qdisc (Queuing Discipline): キューイング規則。どのパケットを先に送り、どれを待機させ、どれを破棄するかを決定します。
- Class: データを格納するクラス(コンテナ)。100Mbps の回線を、SSH 用に 20Mbps、Web 用に 80Mbps といった具合に分割できます。
- Filter: フィルター。郵便物の仕分け係のように、ポート 22 のパケットを SSH クラスへ、ポート 80 を Web クラスへと振り分けます。
HTB (Hierarchical Token Bucket) による実践的な QoS 設定
HTB は、帯域の「借用 (borrowing)」機能があるため、最も推奨される選択肢です。SSH クラスが空いている場合、Web クラスはその余剰帯域を借りて処理を高速化できます。
要件:100Mbps の回線を以下の3種類のトラフィックに分割する:
- SSH (Port 22): 最優先、最低 20Mbps。
- Web (Port 80, 443): 最低 50Mbps。
- その他: 残り (10-30Mbps)。
ステップ 1:ルートキューの初期化
sudo tc qdisc add dev eth0 root handle 1: htb default 30
分類されないすべてのトラフィックは、デフォルトでクラス 30 に振り分けられます。
ステップ 2:総帯域の定義
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit ceil 100mbit
ステップ 3:クラスの細分化
# SSH:優先度 1 (prio 1)
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 20mbit ceil 100mbit prio 1
# Web:優先度 2
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 50mbit ceil 100mbit prio 2
# その他:最低優先度
sudo tc class add dev eth0 parent 1:1 classid 1:30 htb rate 10mbit ceil 100mbit prio 3
ceil 100mbit パラメータにより、回線に空きがある場合に子クラスが速度を上限まで引き上げることが可能になります。
ステップ 4:フィルターの適用
# ポート 22 のトラフィックをクラス 1:10 に送る
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 22 0xffff flowid 1:10
# ポート 80 のトラフィックをクラス 1:20 に送る
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip dport 80 0xffff flowid 1:20
現場からの教訓
かつて、データベースクラスタで謎のネットワーク遅延が発生したことがありました。トラフィック総量は多くないのに、Ping が時々 500ms まで跳ね上がるのです。tc -s qdisc show を実行したところ、キューが頻繁に溢れている(オーバーフロー)ことがわかりました。
原因は、圧縮されたログを短時間に大量に転送するプロセスでした。解決策として burst パラメータを調整しました。これにより、DB の小さなパケットが「割り込み」で先に処理され、巨大なログの塊は順番待ちをするように改善されました。
tc を使用する際の重要な注意点
- 送信(Egress)のみに作用:
tcは出ていくトラフィックの管理に非常に優れています。受信(Ingress)トラフィックを制限するには、仮想インターフェースifbを使用したより複雑な設定が必要です。 - 単位に注意:
mbitはメガビット、mbyteはメガバイトです。ビットとバイトを間違えると、実際の速度が8倍も異なってしまいます。 - サーバーからロックアウトされないように: リモートサーバーで
tcを試す前に、at now + 5 minutesコマンドでtc設定を自動削除するように予約しておきましょう。誤ってポート 22 を絞りすぎてしまっても、やり直すチャンスが残ります。
tc をマスターすることは、単に速度を制限することではありません。ピーク時でもシステムを安定させるための、リソース配分の芸術なのです。

