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

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

的工作原理或测试环境理解有偏差。

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

Post AI

博客文章ai生成器

Linux tc命令流量控制使用方法51

查看详情 Linux tc命令流量控制使用方法

一个最核心的误区是:

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 操作系统 字节 端口 工具 路由 常见问题 为什么 子类 Filter Token 接口 class default http linux ssh

上一篇
下一篇