#server-performance

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

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

hero section cover

使用 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 佇列紀律(qdisc)。 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 的專用伺服器

博客

本周特色

更多文章
iperf3 教學指南:在 Linux 與 Windows 上測試網路速度
#bandwidth#server-performance

iperf3 教學指南:在 Linux 與 Windows 上測試網路速度

在 Linux 和 Windows 系統上安裝 iperf3、執行頻寬測試,並調整 TCP 緩衝區以獲得準確結果。涵蓋 UDP、雙向及 10GbE+ 測試

10 分鐘閱讀 - 2026年5月7日

#server-performance

針對 Linux 伺服器工作負載最佳化所調校的設定檔

16 分鐘閱讀 - 2026年6月9日

更多文章