我有一台Linux多网口主机,搭建了一个网关,本文记录一下实现限流功能。
- 基于
tc工具(Traffic Control,流量控制), - 结合HTB队列规则(Hierarchical Token Bucket,分层令牌桶)
- ifb虚拟设备
实现网关对不同终端、不同方向流量的精准限流,覆盖下行、上行限流场景及完整运维流程。
一、核心组件工具
1.1 关键工具与模块
-
tc:Linux内核自带的流量控制工具,支持队列规则(qdisc)、流量类别(class)、过滤器(filter)三层配置,可实现带宽限制、优先级调度等功能。
-
HTB队列规则:核心限流规则,支持层级化带宽分配,可设置最小保障带宽(rate)和最大突发带宽(ceil),适配网关多终端共享带宽场景。
-
ifb模块:虚拟网络接口模块,用于解决Linux对“上行流量”直接限流的局限性,通过流量重定向实现上行带宽精准控制。
1.2 网关流量方向定义
网关限流需明确流量方向,避免配置混淆:
-
下行流量:外网→网关→内网终端(如终端浏览网页、下载文件),限流需配置在网关的外网网卡(如ens36)。
-
上行流量:内网终端→网关→外网(如终端上传文件、访问外网服务),需通过ifb虚拟设备重定向流量后限流。
1.3 常用基础命令
用于查看、验证限流配置,排查问题:
# 查看所有网卡的队列规则
tc qdisc show|ls
# 查看指定网卡(如ens36)的队列规则
tc qdisc show dev ens36
# 查看指定网卡的过滤器配置(流量匹配规则)
tc filter show dev ens36
# 查看指定网卡的流量类别(带宽分配规则)
tc class show dev ens36
二、网关限流实操配置
本文以网关外网网卡ens36、内网网段10.100.0.0/24为例,实现多场景限流配置,所有命令需以root权限执行。
2.1 场景1:内网终端下行限流(外网→内网)
限制指定内网终端(如10.100.0.99)的下行带宽为10Mbit,保障其他终端网络体验。
-
添加根HTB队列规则:在网关外网网卡ens36上创建根队列,作为所有限流类的父节点。
tc qdisc add dev ens36 root handle 1: htb
说明:handle 1:为根队列句柄(主类标识),后续子类需基于此关联。 -
创建下行限流类:定义带宽限制规则,rate为最小保障带宽(此处与ceil一致,即固定限流10Mbit)。
tc class add dev ens36 parent 1: classid 1:10 htb rate 10mbit ceil 10mbit
说明:classid 1:10为子类标识(主类1+次类10),parent 1:表示继承根队列属性。 -
配置过滤器(匹配目标终端):将访问内网终端10.100.0.99的下行流量,引导至上述限流类。
tc filter add dev ens36 protocol ip parent 1:0 prio 1 u32 \ match ip dst 10.100.0.99/32 \ flowid 1:10说明:match ip dst匹配目标IP(内网终端),flowid 1:10指定流量对应限流类,prio 1为过滤器优先级(数值越小优先级越高)。
2.2 场景2:内网终端上行限流(内网→外网)
Linux无法直接对网卡入口流量(上行)限流,需通过ifb虚拟设备重定向流量,再对虚拟设备配置限流规则。
- 加载ifb模块并启用虚拟设备:`# 加载ifb模块(一次性加载,重启后需重新加载)
modprobe ifb
启用ifb0虚拟设备(可支持多个虚拟设备,如ifb0、ifb1)
ip link set dev ifb0 up`
- 重定向外网网卡入口流量至ifb0:将ens36的上行流量(内网→外网)转发到ifb0处理。
`# 为ens36添加 ingress 队列(用于捕获入口流量)
tc qdisc add dev ens36 handle ffff: ingress
配置过滤器,将所有入口IP流量重定向至ifb0
tc filter add dev ens36 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0说明:handle ffff:是ingress队列的固定句柄,match u32 0 0`表示匹配所有流量。
- 为ifb0配置HTB限流规则:限制10.100.0.99访问指定外网IP(183.66.100.19)的上行带宽为20Mbit。
`# 为ifb0添加根HTB队列
tc qdisc add dev ifb0 root handle 1: htb
创建上行限流类(20Mbit固定限流)
tc class add dev ifb0 parent 1: classid 1:20 htb rate 20mbit ceil 20mbit
配置过滤器,匹配指定内网IP→外网IP的流量
tc filter add dev ifb0 protocol ip parent 1:0 prio 1 u32
match ip src 10.100.0.99/32
match ip dst 183.66.100.19/32
flowid 1:20`
2.3 场景3:网段批量限流与端口级限流
针对网关场景的批量控制需求,可扩展配置网段限流和端口级限流,适配不同业务场景。
3.1 内网网段整体限流(如10.100.0.0/24)
限制整个内网网段上行带宽不超过100Mbit,避免网段占用全部网关带宽:
# 在ifb0上创建网段限流类(rate 100mbit,ceil 120mbit允许突发)
tc class add dev ifb0 parent 1: classid 1:30 htb rate 100mbit ceil 120mbit
# 匹配整个内网网段流量
tc filter add dev ifb0 protocol ip parent 1:0 prio 2 u32 \
match ip src 10.100.0.0/24 \
flowid 1:30
说明:优先级设为2(低于单终端限流的优先级1),确保单终端限流优先于网段限流生效。
3.2 端口级限流(如HTTP/HTTPS服务)
限制内网终端访问外网80(HTTP)、443(HTTPS)端口的下行带宽为5Mbit,保障核心业务流量:
# 在ens36上创建端口限流类
tc class add dev ens36 parent 1: classid 1:40 htb rate 5mbit ceil 5mbit
# 匹配目标端口为80和443的流量
tc filter add dev ens36 protocol ip parent 1:0 prio 1 u32 \
match ip dport 80 0xffff \
match ip dport 443 0xffff \
flowid 1:40
说明:0xffff为端口掩码,确保精准匹配指定端口。
三、限流配置复原(清理规则)
测试完成或需重置配置时,需清理所有队列规则、类和过滤器,避免残留配置影响网络。
3.1 清理所有网卡队列规则与类
for dev in $(ip link show | grep '^[0-9]' | awk '{print $2}' | sed 's/://'); do
echo "Cleaning up tc rules for device: $dev"
tc qdisc del dev "$dev" root 2>/dev/null
done
3.2 清理ingress队列与ifb设备
# 清理所有网卡的ingress队列
for dev in $(ip link show | grep '^[0-9]' | awk '{print $2}' | sed 's/://'); do
echo "Cleaning up ingress qdisc for device: $dev"
tc qdisc del dev "$dev" ingress 2>/dev/null
done
# 禁用并卸载ifb模块
ip link set dev ifb0 down 2>/dev/null
rmmod ifb 2>/dev/null
说明:2>/dev/null用于忽略“规则不存在”的报错,使脚本更稳健。
四、配置持久化(避免重启失效)
上述配置为临时生效,重启网络服务或系统后会丢失,需通过脚本实现持久化。
4.1 编写限流启动脚本
# 创建脚本文件 /usr/local/bin/gateway-traffic-limit.sh
vi /usr/local/bin/gateway-traffic-limit.sh
脚本内容(整合上述所需限流规则,按需调整参数):
#!/bin/bash
# 加载ifb模块
modprobe ifb
ip link set dev ifb0 up
# 清理原有规则
for dev in $(ip link show | grep '^[0-9]' | awk '{print $2}' | sed 's/://'); do
tc qdisc del dev "$dev" root 2>/dev/null
tc qdisc del dev "$dev" ingress 2>/dev/null
done
# 配置ens36下行限流(10.100.0.99 下行10Mbit)
tc qdisc add dev ens36 root handle 1: htb
tc class add dev ens36 parent 1: classid 1:10 htb rate 10mbit ceil 10mbit
tc filter add dev ens36 protocol ip parent 1:0 prio 1 u32 match ip dst 10.100.0.99/32 flowid 1:10
# 配置上行限流(重定向流量至ifb0,10.100.0.99上行20Mbit)
tc qdisc add dev ens36 handle ffff: ingress
tc filter add dev ens36 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
tc qdisc add dev ifb0 root handle 1: htb
tc class add dev ifb0 parent 1: classid 1:20 htb rate 20mbit ceil 20mbit
tc filter add dev ifb0 protocol ip parent 1:0 prio 1 u32 match ip src 10.100.0.99/32 match ip dst 183.66.100.19/32 flowid 1:20
echo "Gateway traffic limit rules applied successfully!"
4.2 配置开机自启
# 赋予脚本执行权限
chmod +x /usr/local/bin/gateway-traffic-limit.sh
# 方式1:通过rc.local自启(适用于CentOS 7、Ubuntu)
echo "/usr/local/bin/gateway-traffic-limit.sh" >> /etc/rc.local
chmod +x /etc/rc.local
# 方式2:通过systemd自启(适用于CentOS 8、Ubuntu 18+)
cat > /etc/systemd/system/gateway-limit.service << EOF
[Unit]
Description=Gateway Traffic Limit Service
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/gateway-traffic-limit.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
# 启用并启动服务
systemctl daemon-reload
systemctl enable gateway-limit.service
systemctl start gateway-limit.service
五、关键参数与注意事项
5.1 核心参数说明
-
rate:流量控制类的最小保障带宽,即使网络拥堵,也会为该类保留此带宽。
-
ceil:流量控制类的最大突发带宽,当网络空闲时,该类可占用的最大带宽,超过rate但不超过ceil。
-
parent:指定流量类的父类句柄,形成层级关系,父类带宽需大于等于子类带宽之和。
-
prio:过滤器优先级,数值越小优先级越高,当流量匹配多个过滤器时,优先执行高优先级规则。