Linux tc命令流量控制使用方法(使用方法.命令.流量控制.Linux.tc...)

wufei123 发布于 2025-09-24 阅读(12)
tc命令是Linux中用于网络流量控制的强大工具,可对出站流量进行限速、优先级划分和整形。其核心机制基于qdisc(排队规则)、class(类)和filter(过滤器)三大组件。tbf适用于简单限速,htb则支持复杂的分级带宽管理,如为SSH、HTTP分配不同优先级和带宽。常见问题包括误用于入站流量、旧规则残留、过滤器匹配错误及测试方法不当。排查需检查规则状态与统计信息。tc常与iptables协同:iptables在mangle表中通过MARK为目标流量打标记,tc使用fw过滤器根据标记将流量导向特定class进行调度,从而实现精细化QoS策略。

linux tc命令流量控制使用方法

tc
命令是 Linux 系统中一个强大但配置起来也颇为复杂的流量控制工具。简单来说,它就是你操作系统层面用来精细管理网络数据包“排队”和“发送”的“交通警察”。它允许你对出站(甚至部分入站)流量进行限速、优先级设置、流量整形,从而优化网络性能,确保关键应用的服务质量(QoS)。在我看来,掌握
tc
的基本原理和常用配置,对于任何需要进行网络性能调优的系统管理员或开发者来说,都是一项非常有价值的技能,尽管它确实有点学习曲线。 解决方案

使用

tc
命令进行流量控制的核心在于理解其三个主要概念:
qdisc
(queuing discipline,排队规则)、
class
(类) 和
filter
(过滤器)。
  1. qdisc
    (排队规则): 这是流量控制的基础。每个网络接口(如
    eth0
    )都有一个根
    qdisc
    。所有出站数据包都必须经过这个
    qdisc
    。你可以选择不同的
    qdisc
    类型来定义数据包如何被排队和调度。
  2. class
    (类): 某些
    qdisc
    (如
    HTB
    )是分层的,允许你在一个
    qdisc
    下创建多个“类”。每个类可以有自己的带宽限制和优先级,并且可以进一步包含子
    qdisc
    和子类。
  3. filter
    (过滤器): 过滤器用于将特定的数据包导向特定的
    class
    qdisc
    。你可以根据源/目的 IP、端口、协议等多种条件来匹配数据包。

基本限速示例 (使用

tbf
- Token Bucket Filter):

tbf
是最简单的
qdisc
之一,适用于对整个接口的出站流量进行硬性限速。
# 1. 清除eth0接口上可能存在的旧规则,避免冲突
sudo tc qdisc del dev eth0 root

# 2. 在eth0接口上添加一个tbf qdisc,限制出站速度为100kbit/s,
#    允许突发流量达到10kbit,并设置延迟为70ms(数据包在队列中等待的最长时间)
sudo tc qdisc add dev eth0 root tbf rate 100kbit burst 10kbit latency 70ms

# 3. 验证规则是否生效
sudo tc qdisc show dev eth0

分级限速与优先级示例 (使用

HTB
- Hierarchical Token Bucket):

HTB
tc
中最常用也最强大的
qdisc
之一,它允许你创建复杂的流量分级和优先级策略。

假设我们想将

eth0
的总出站带宽限制在 100Mbps,然后为 SSH 流量(端口 22)分配 50Mbps 的高优先级带宽,为 HTTP 流量(端口 80)分配 20Mbps 的中优先级带宽,其余流量则走默认的低优先级通道。
# 1. 清除eth0接口上的所有现有规则
sudo tc qdisc del dev eth0 root

# 2. 创建一个HTB根qdisc。handle 1: 是这个qdisc的标识符。
#    default 20 表示所有未被特定过滤器匹配的流量都将进入classid 1:20。
sudo tc qdisc add dev eth0 root handle 1: htb default 20

# 3. 创建一个主类 (parent 1:),定义总的可用带宽。
#    classid 1:1 是这个主类的标识符。
#    rate 100mbit 是承诺带宽,ceil 100mbit 是最大可用带宽。
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit ceil 100mbit

# 4. 创建子类,分配给不同类型的流量。
#    a. SSH流量类 (高优先级)
#       parent 1:1 表示它是主类1:1的子类。classid 1:10 是其标识符。
#       rate 50mbit 是承诺带宽,ceil 80mbit 是在有空闲时可以突发到的最大带宽。
#       prio 1 表示优先级最高(数字越小优先级越高)。
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 50mbit ceil 80mbit prio 1

#    b. HTTP流量类 (中优先级)
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 20mbit ceil 50mbit prio 2

#    c. 默认流量类 (低优先级,用于所有未匹配的流量)
#       这个类的rate和ceil可以根据实际情况设置,或者让它共享剩余带宽。
sudo tc class add dev eth0 parent 1:1 classid 1:30 htb rate 10mbit ceil 30mbit prio 3

# 5. 使用过滤器将特定流量分类到对应的类。
#    protocol ip 表示匹配IP协议流量。prio 定义过滤器本身的优先级。
#    u32 过滤器允许我们基于IP头部字段进行匹配。
#    match ip dport 22 0xffff 表示匹配目的端口为22的TCP/UDP流量。
#    flowid 1:10 表示将匹配到的流量导向classid 1:10。

#    a. SSH流量 (目的端口22)
sudo tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip dport 22 0xffff flowid 1:10

#    b. HTTP流量 (目的端口80)
sudo tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip dport 80 0xffff flowid 1:20

# 6. 验证所有规则
sudo tc -s qdisc show dev eth0
sudo tc -s class show dev eth0
sudo tc -s filter show dev eth0

# 7. 删除所有规则
# 当你不再需要这些规则时,记得删除它们。
# sudo tc qdisc del dev eth0 root

这个

HTB
示例虽然看起来复杂,但它正是
tc
强大之处的体现。通过这种方式,你可以为服务器上的不同服务、不同用户或不同应用分配和保障带宽,确保关键业务的流畅运行。 为什么我的
tc
规则似乎没有生效?

这绝对是

tc
新手最常遇到的“坑”之一,甚至我自己也时不时会在这里跌倒。
tc
规则不生效,往往不是命令本身错了(虽然语法错误也常见),而是对
tc
的工作原理或测试环境理解有偏差。 Teleporthq Teleporthq

一体化AI网站生成器,能够快速设计和部署静态网站

Teleporthq182 查看详情 Teleporthq

一个最核心的误区是:

tc
默认只控制
egress
(出站)流量。 也就是说,你设置的规则,只会影响从你的网卡
eth0
发出去的数据包。如果你想控制 进入
eth0
的数据包(
ingress
流量),情况就复杂多了。虽然
tc
有一个
ingress qdisc
,但它功能有限,主要用于丢弃超速流量,不能像
egress
那样进行复杂的整形和优先级划分。通常,对于入站流量的控制,你需要结合
iptables
进行数据包标记,然后在一个 其他 接口的
egress
端进行整形,或者利用一些更高级、更复杂的内核模块(比如
IMQ
,但它现在已经不推荐使用了)。所以,当你发现规则没生效时,先问问自己:我是在控制出站还是入站流量?

另外,还有几个常见原因:

  • 旧规则残留: 你在添加新规则之前,有没有彻底清除掉
    eth0
    上可能存在的旧规则?
    sudo tc qdisc del dev eth0 root
    这一步至关重要。如果存在冲突的规则,新的可能就不会被应用,或者行为不符合预期。
  • 过滤器匹配问题: 你的
    filter
    规则是否真的匹配到了你想要控制的流量?IP 地址、端口号、协议、甚至
    u32
    匹配的偏移量和掩码,任何一个细节不对,数据包就可能溜走,进入
    default
    类或者根本不受控制。我发现很多人在
    u32
    匹配上容易出错,一个
    0xffff
    的掩码可能就导致匹配不精确。
  • 测试方法不当: 你是如何测试限速效果的?仅仅是
    ping
    吗?
    ping
    的流量很小,可能根本触及不到限速阈值。通常,你需要使用
    iperf3
    netcat
    或者实际的大文件下载/上传来产生足够的流量,才能观察到
    tc
    规则的效果。同时,确保你测试的流量确实是通过你设置
    tc
    规则的那个接口。
  • 优先级冲突: 如果你设置了多个
    filter
    ,它们的
    prio
    值很重要。
    tc
    会按照
    prio
    值从小到大(优先级从高到低)的顺序处理过滤器。一个优先级较高的、匹配范围较广的过滤器,可能会在更具体的过滤器之前捕获到流量。
  • 内核模块缺失: 虽然现代 Linux 内核通常都预装了
    tc
    所需的模块,但如果你的系统是高度定制的,或者非常老旧,可能需要检查
    sch_htb
    sch_tbf
    等模块是否已加载 (
    lsmod | grep sch_
    )。

遇到问题,最有效的排查方式是使用

sudo tc -s qdisc show dev eth0
sudo tc -s class show dev eth0
sudo tc -s filter show dev eth0
命令,它们会显示当前规则的详细状态和统计信息,包括通过每个
qdisc
class
的数据包数量和字节数,这能帮助你判断流量是否真的进入了你预期的队列。
tc
iptables
在流量控制中如何协同工作?

tc
iptables
在 Linux 网络栈中扮演着不同的角色,但它们可以非常优雅地协同工作,实现更精细、更灵活的流量控制策略。简单来说,
iptables
负责识别和标记数据包,而
tc
则负责根据这些标记调度和整形数据包。

iptables
的强大之处在于它能够基于非常丰富的条件来检查和修改数据包。它可以查看源/目的 IP、端口、协议、TCP 标志位、连接状态,甚至数据包的特定内容。在流量控制的场景下,
iptables
最常用的功能是使用
MARK
CONNMARK
目标,在
mangle
表中为数据包打上一个数字标记。这个标记本身不会改变数据包的内容,但它会随着数据包在内核中传递,可以被其他模块(比如
tc
)读取。

协同工作流程:

  1. iptables
    标记数据包: 你可以在
    iptables
    mangle
    表中定义规则,根据你需要的条件(例如,来自特定 IP 的流量、去往特定端口的流量、特定协议的流量等)为数据包打上一个唯一的数字标记。
    # 示例:标记所有源IP为192.168.1.100的出站流量,标记值为10
    sudo iptables -t mangle -A POSTROUTING -s 192.168.1.100 -j MARK --set-mark 10
    
    # 示例:标记所有目的端口为80(HTTP)的出站TCP流量,标记值为20
    sudo iptables -t mangle -A POSTROUTING -p tcp --dport 80 -j MARK --set-mark 20
    
    # 确保路由后,标记仍然存在。PREROUTING 也可以,但POSTROUTING更靠近tc的egress。
    # 如果要对入站流量进行标记,通常在PREROUTING链进行,但要记住tc只能在出站接口整形。

    注意:

    MARK
    目标会给单个数据包打标记。如果你想标记整个连接的所有数据包,可以使用
    CONNMARK
    ,它会将
    MARK
    值保存到连接跟踪表中,并应用到该连接的所有后续数据包。
  2. tc
    根据标记过滤和整形: 在
    tc
    的过滤器中,你可以使用
    fw
    (firewall mark) 过滤器来匹配
    iptables
    设置的标记,然后将匹配到的数据包导向特定的
    class
    qdisc
    进行流量整形。
    # 假设你已经设置了一个HTB根qdisc和主类,例如:
    # sudo tc qdisc add dev eth0 root handle 1: htb default 30
    # sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit ceil 100mbit
    
    # 创建一个子类1:10,用于处理标记为10的流量
    sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 10mbit ceil 20mbit prio 1
    
    # 创建一个子类1:20,用于处理标记为20的流量
    sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 5mbit ceil 15mbit prio 2
    
    # 使用fw过滤器匹配iptables的标记
    # prio 1 表示这个过滤器本身的优先级。handle 10 fw 匹配标记值为10的数据包。
    sudo tc filter add dev eth0 parent 1: protocol ip prio 1 handle 10 fw flowid 1:10
    
    # 匹配标记值为20的数据包
    sudo tc filter add dev eth0 parent 1: protocol ip prio 2 handle 20

以上就是Linux tc命令流量控制使用方法的详细内容,更多请关注知识资源分享宝库其它相关文章!

相关标签: linux 操作系统 字节 端口 工具 栈 路由 常见问题 为什么 子类 Filter Token 接口 栈 class default http linux ssh 大家都在看: 如何在Linux命令行中进行文件操作? 如何在Linux中监控网络接口流量? Linux命令行中top与htop命令的对比与使用 如何在Linux命令行中使用alias命令提高效率 如何在Linux中排查网络拥塞?

标签:  使用方法 命令 流量控制 

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。