Linux 流量控制 (tc):實用指南

12 分鐘閱讀 - 2026年6月5日

hero section cover
目錄
  • Linux 流量控制 (tc):實用指南
  • tc 的運作方式
  • 在 Linux 伺服器上設定 tc
  • 使用 HTB 進行出站流量整形
  • 使用 IFB 塑造入站流量
  • 使用 DSCP 進行流量優先級排序
  • 監控與疑難排解
分享

使用 tc 在 Linux 上控制頻寬、優先處理流量,以及塑造入口和出口。真實伺服器的 HTB、IFB、DSCP 和 fq_codel 配置。

Linux 流量控制 (tc):實用指南

Linux 的 tc 指令可讓您直接控制伺服器處理網路流量的方式。 您可以透過單一工具,設定各服務的頻寬上限、確保在大量傳輸量激增時 SSH 等互動式連線仍能保持響應,並同時形塑進出流量。本指南涵蓋核心概念、可運作的 HTB 設定、使用 IFB 進行入站流量形塑、基於 DSCP 的優先級排序,以及發生故障時的除錯方法。


 

tc 的運作方式

每個 tc 設定皆由四個可變組件構成:

  • qdisc(佇列紀律)。附著於網路介面的排程器,負責決定封包的入隊與出隊方式。
  • Class。這是具有類別區分的 qdisc 內的子區分。可將其視為擁有自身速限的車道。
  • Filter篩選器)。檢查封包標頭(IP 位址、埠號、標記),並將每個封包分配至特定類別。
  • Action(動作)。當封包符合條件時將執行的操作:轉發、丟棄、重定向。

這些元件共同構成一棵樹狀結構。封包從根 qdisc 進入,經過篩選器,透過 major:minor ,最終排入葉節點 qdisc 隊列以待傳輸。

若需比基於埠的匹配更複雜的處理,請先在 mangle 表中使用 iptablesnftables 標記封包,然後使用 fw filter tc 中的filter u32 規則來處理每種流量類型。

出站與入站

方向至關重要。核心可以對出站封包進行緩衝和延遲,這正是實現真正流量整形的關鍵。當您看到入站封包時,它們已經通過網路傳輸,因此除非您先將其重定向到 IFB 裝置,否則您只能對其進行流量監控(超過閾值時丟棄)。

功能出站入站
方向出站入站
流量整形原生需要 IFB
流量監控受支援已支援
典型用途QoS、頻寬共享、流量調控速率限制、基本 DDoS 緩解

您實際會使用的 qdisc

  • HTB(分層令牌桶)。具類別。當您希望為每個服務保證最低頻寬,並能從其他類別借用未使用容量時,請使用此選項。
  • TBF(Token Bucket Filter)。無類別。當您僅需將整個介面限制在單一速率時使用。
  • fq_codel(公平佇列控制延遲)。 結合了每流公平性與主動佇列管理,以消除緩衝區膨脹。自 systemd 217 起,它已成為大多數 Linux 發行版的預設 qdisc,並在 RHEL 9 中預設搭載。請務必將其作為 HTB 類別下的葉節點 qdisc 附加,否則單一貪婪流量便可能佔用整個類別。

在 Linux 伺服器上設定 tc

tciproute2 套件一併提供。在 Debian 和 Ubuntu 上,請使用 apt-get install iproute2。在 RHEL 及其衍生版本上, yum install iproute。您需要 root 或 sudo 權限。

首先請確認正確的介面名稱。介面名稱錯誤是設定檔無聲無息地無法生效的最常見原因:

ip link show

檢查介面上的現有設定,包括即時計數器:

tc -s qdisc show dev eth0

在套用新設定前,請清除任何現有的 root qdisc,以避免 RTNETLINK answers: File exists 發生錯誤:

tc qdisc del dev eth0 root 2>/dev/null || true

若您是要更新現有規則而非從頭開始,請使用 replace 而非 add 以進行原子交換。

TSO 和 GSO 等硬體卸載功能會以干擾流量整形的方式封裝封包。請在進行流量整形的介面上將其關閉:

sudo ethtool -K eth0 tso off gso off

fq_codel 為新介面的系統級預設 qdisc:

sysctl -w net.core.default_qdisc=fq_codel

對於繁忙的伺服器,建議搭配 BBR 擁塞控制演算法(內核 4.9+)。BBR 能在不增加佇列長度的情況下維持高吞吐量:

sysctl -w net.ipv4.tcp_congestion_control=bbr

若您透過 SSH 配置遠端主機,請養成一項安全習慣:開啟第二個連線並預先準備好 tc qdisc del dev eth0 root 準備好待貼內容。錯誤的過濾規則可能讓你瞬間被鎖在系統外。

使用 HTB 進行出站流量整形

HTB 讓您能為每項服務設定保證的最低值(rate)及上限(ceil)。未使用的頻寬將依優先順序分配給有需求的使用者。以下是一個適用於 1 Gbps 上行鏈路的實用三層架構設定。

建立根 HTB 佇列調度器。 default 30 會將任何未分類的封包傳送至 class 1:30 ,而非讓其繞過您的規則:

tc qdisc add dev eth0 root handle 1: htb default 30

將總吞吐量限制在 900 Mbps。請務必將形塑值設定在實際鏈路容量稍低之處,否則佇列將形成於您無法控制的上游路由器或數據機上:

tc class add dev eth0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbit

定義服務層級。較低的 prio 值將優先獲得未使用的頻寬:

# High priority: web and API traffic
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 500mbit ceil 900mbit prio 1
 
# Medium priority: database replication
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 300mbit ceil 900mbit prio 2
 
# Low priority: bulk and backup traffic
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 100mbit ceil 900mbit prio 3

fq_codel 作為各服務等級的末端 qdisc,以防止單一流量佔據其等級:

tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel
tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel
tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel

現在對流量進行分類。對於簡單的埠位比對, u32 是最快的:

tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
  match ip dport 443 0xffff flowid 1:10

對於任何需要狀態追蹤的情況,請在 iptables 中進行標記,並根據標記進行匹配 fw:

iptables -t mangle -A OUTPUT -p tcp --dport 5432 -j MARK --set-mark 2
tc filter add dev eth0 protocol ip parent 1:0 prio 2 handle 2 fw flowid 1:20

使用 IFB 塑造入站流量

您無法原生地對入站流量進行流量整形,因為當封包抵達時,它已經佔用了您的頻寬。解決方案是將入站流量重定向至中間功能區塊 (IFB) 虛擬介面,在此處,核心會將其視為出站流量,並允許您套用基於類別的 qdisc。

載入模組並啟用介面:

modprobe ifb numifbs=1
ip link set dev ifb0 up

在實體介面上新增一個入站 qdisc,並將所有流量重定向至 ifb0:

tc qdisc add dev eth0 ingress handle ffff:
tc filter add dev eth0 parent ffff: protocol all u32 \
  match u32 0 0 action mirred egress redirect dev ifb0

從此處開始, ifb0 該介面便會像其他介面一樣運作。請如同對待出站流量般,將您的 HTB 樹精確套用至該介面:

tc qdisc add dev ifb0 root handle 1: htb default 30
tc class add dev ifb0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 500mbit ceil 900mbit prio 1

使用 DSCP 進行流量優先級排序

DSCP(差異化服務代碼點)會在 TOS 位元組中以 6 位元值標記封包,因此您的 tc 過濾器可依據標籤進行分類,而非在規則集中遍尋各端口。在匹配 DSCP 時 tc進行 DSCP 比對時,請將數值向左移位 2 位元。DSCP EF (46) 將變為 0xb8。該遮罩 0xfc 將 6 位元 DSCP 位元與 2 位元 ECN 位元隔開。

針對伺服器工作負載的合理預設對應關係:

流量類型DSCPTOS 十六進位範例
互動式EF0xb8SSH、DNS、VoIP
商務AF410x88HTTP、HTTPS、API
批量CS10x20備份、FTP、套件更新
盡力而為CS00x00其他所有項目

在出站封包觸及您的 tc 過濾器之前,在 iptables 中為其標記:

iptables -t mangle -A OUTPUT -p tcp --dport 22 -j DSCP --set-dscp 46

接著在 tc 並將其路由至正確的 HTB 類別:

# EF (SSH, VoIP) goes to the high-priority class
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
  match ip tos 0xb8 0xfc flowid 1:10
 
# AF41 (web traffic) goes to the medium class
tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 \
  match ip tos 0x88 0xfc flowid 1:20
 
# CS1 (bulk) goes to the low-priority class
tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 \
  match ip tos 0x20 0xfc flowid 1:30

監控與疑難排解

您將經常使用的三個指令:

tc -s qdisc show dev eth0
tc -s class show dev eth0
tc -s filter show dev eth0

請留意 droppedoverlimits 計數器。丟包表示佇列已飽和;超出限值則表示您已觸及類別上限,內核不得不延遲或捨棄流量。若要查看即時狀態:

watch -n 1 'tc -s class show dev eth0'

添加 -d 以查看內部參數(目標、間隔、量子),並 -j 若要將輸出導向至指標堆疊,請使用以產生 JSON 格式。搭配 ss -tin 可查看 TCP 層的 RTT 估算值與重傳次數。

大多數故障可歸納為以下幾種:

症狀可能原因解決方法
RTNETLINK answers: File exists根 qdisc 已設定tc qdisc del dev eth0 root 首先
規則已套用但流量未受限制介面設定錯誤,或 TSO/GSO 仍啟用請透過 ip link show,並使用 ethtool -K
過濾器從未匹配埠號/IP 語法錯誤或子網掩碼對齊不當新增反制措施,並在 tc -s filter show
重新開機後規則消失設定僅存在於記憶體中封裝成腳本,並透過 systemd 或 NetworkManager 調度器呼叫
優先級流量延遲過高缺乏葉節點 qdisc,或突發值過低fq_codel 至 leaf 類別,提高 burst

若因設定錯誤導致系統無法存取,重置方法很簡單:

tc qdisc del dev eth0 root

tc 無法憑空製造您原本沒有的頻寬,但在配置完善的上行鏈路上,這將決定系統是能維持可預測的效能,還是會在某個租戶啟動大流量傳輸的瞬間導致伺服器崩潰。若您需要原始頻寬並希望自由地進行流量整形,不妨看看 FDC 的專用伺服器

博客

本周特色

更多文章
Linux 流量控制 (tc):實用指南

Linux 流量控制 (tc):實用指南

使用 tc 在 Linux 上控制頻寬、優先處理流量,以及塑造入口和出口。真實伺服器的 HTB、IFB、DSCP 和 fq_codel 配置。

12 分鐘閱讀 - 2026年6月5日

為什麼擁有一個強大且不計費的 VPS 是很重要的?

7 分鐘閱讀 - 2025年5月9日

更多文章