第一章:环境规划与内核调优
1.1 网络拓扑
假设我们的Linux服务器有三张网卡:
eth0 (外网):连接光猫,IP
192.168.1.100/24,网关192.168.1.1。eth1 (内网):连接核心交换机,IP
10.0.0.1/24。eth2 (管理口):可选,用于SSH管理。
我们的目标是:内网用户(10.0.0.0/24)通过Linux网关上网,并对特定IP进行带宽保障。
1.2 开启内核转发与优化
Linux默认不转发IP包,需要手动开启。
# 临时开启 echo 1 > /proc/sys/net/ipv4/ip_forward # 永久生效,写入 sysctl.conf cat >> /etc/sysctl.conf << EOF net.ipv4.ip_forward = 1 # 防止 SYN 攻击,优化队列 net.core.netdev_max_backlog = 5000 net.ipv4.tcp_syncookies = 1 EOF sysctl -p1.3 配置NAT(网络地址转换)
使用iptables让内网机器共享外网IP上网。这是网关的核心功能。
# 清除旧规则 iptables -F iptables -t nat -F # 设置默认策略 iptables -P INPUT DROP iptables -P FORWARD DROP # 允许内网转发和已建立的连接 iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -s 10.0.0.0/24 -j ACCEPT # 关键:SNAT(源地址转换),伪装成外网IP出去 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE大神注解:这里使用
MASQUERADE(伪装)而非SNAT,是因为外网IP可能变动(PPPoE拨号),MASQUERADE会自动获取出口IP,更加灵活。
第二章:流量整形基石——理解TC与队列规则
流量整形并非“限速”那么简单。粗暴地把带宽砍半,会导致网络波动。我们需要优先级控制。
2.1 为什么选HTB?
Linux TC支持多种算法,如pfifo_fast(先进先出)、SFQ(随机公平队列)。但在企业环境,HTB是首选。
原理:类似于银行金库(总带宽)。根是总金库,子类(Subclass)是不同部门或用户的账户。我们可以给总经理开设“VIP窗口”(保证带宽),给下载部门开设“普通窗口”(限制带宽)。
概念区分:
ceiling(上限):最高能借多少带宽。
rate(承诺速率):最低保证多少带宽。
2.2 清除旧规则(热身)
在开始写脚本前,先确保网卡干净。
# 查看当前 qdisc tc qdisc show dev eth1 # 删除(如果有旧规则) tc qdisc del dev eth1 root第三章:实战脚本编写——让带宽“听话”
这是一个完整的Shell脚本,我们命名为/usr/local/bin/bandwidth_control.sh。
3.1 定义变量(适配不同环境)
#!/bin/bash # 出口网卡(内网) DEV="eth1" # 总带宽(单位:kbit),假设下行100Mbps,上行20Mbps(我们控制下行,即内网口) # 注意:家庭宽带上下行不对等,这里是控制从外网进来的流量,所以限制eth1的入口更准确,但此处为了演示针对内网用户的下行限速,我们控制eth1的出口(即发往内网的数据)。 # 换算:100Mbps = 102400 kbit TOTAL_RATE="102400" TOTAL_CEIL="102400" # 定义具体IP与分组 # 1: 总经理办公室(VIP) - 保证80M,借满100M CEO_IP="10.0.0.88" CEO_RATE="81920" # 80M CEO_CEIL="102400" # 100M # 2: 研发部(高优先级) DEV_IP="10.0.0.99" DEV_RATE="20480" # 20M DEV_CEIL="51200" # 50M # 3: 其他所有人(共享剩余,且优先级最低) OTHER_RATE="10240" # 10M OTHER_CEIL="40960" # 40M3.2 建立HTB根队列与主干类
# 1. 绑定根队列,使用 htb tc qdisc add dev $DEV root handle 1: htb default 30 # 2. 建立主干类(根类) # classid 1:1,这是总带宽池 tc class add dev $DEV parent 1: classid 1:1 htb rate ${TOTAL_RATE}kbit ceil ${TOTAL_CEIL}kbit # 3. 建立子类 # 注意:prio 数值越小优先级越高 # 子类 ID: 1:10 (VIP) tc class add dev $DEV parent 1:1 classid 1:10 htb rate ${CEO_RATE}kbit ceil ${CEO_CEIL}kbit prio 0 # 子类 ID: 1:20 (研发) tc class add dev $DEV parent 1:1 classid 1:20 htb rate ${DEV_RATE}kbit ceil ${DEV_CEIL}kbit prio 1 # 子类 ID: 1:30 (默认/其他人) tc class add dev $DEV parent 1:1 classid 1:30 htb rate ${OTHER_RATE}kbit ceil ${OTHER_CEIL}kbit prio 23.3 附加队列规则(SFQ,保证小包不排队)
如果仅仅有HTB,同一类里的数据流依旧可能发生“大文件抢占小包”的问题。我们需要在每个叶子类上附加sfq(随机公平队列)或fq_codel(控制延迟)。
# 为每个叶子类挂载队列规则 tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10 tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10 tc qdisc add dev $DEV parent 1:30 handle 30: sfq perturb 10
perturb 10表示每10秒改变一次哈希算法,防止某个连接霸占带宽。
3.4 过滤器(核心:通过iptables标记将IP映射到类)
我们需要告诉内核:哪个IP的数据包,应该进入哪个类(Classid)。
这里使用fw(防火墙标记)过滤器,配合iptables的MARK目标。
# 1. 添加过滤器:根据防火墙标记 (handle) 来匹配 tc filter add dev $DEV parent 1:0 protocol ip prio 1 handle 10 fw classid 1:10 tc filter add dev $DEV parent 1:0 protocol ip prio 1 handle 20 fw classid 1:20 tc filter add dev $DEV parent 1:0 protocol ip prio 1 handle 30 fw classid 1:30 # 2. 使用 iptables 给不同IP的流量打标记(mangle表) # 注意:数据包流向是 外网->eth0->Linux->eth1->内网。 # 我们控制的是从 eth1 发出去的数据,所以在 PREROUTING 或 FORWARD 链打标记。 # 这里使用 FORWARD 链,针对源IP打标记(因为对于内网口eth1,出方向数据包源IP是内网IP) # 清除旧标记 iptables -t mangle -F # 总经理 IP 标记为 10 iptables -t mangle -A FORWARD -s ${CEO_IP} -j MARK --set-mark 10 # 研发部 IP 标记为 20 iptables -t mangle -A FORWARD -s ${DEV_IP} -j MARK --set-mark 20 # 其他所有 IP 标记为 30 (这里是取反,排除上面两个IP) iptables -t mangle -A FORWARD -s 10.0.0.0/24 -m mark --mark 0 -j MARK --set-mark 30# 1. 添加过滤器:根据防火墙标记 (handle) 来匹配 tc filter add dev $DEV parent 1:0 protocol ip prio 1 handle 10 fw classid 1:10 tc filter add dev $DEV parent 1:0 protocol ip prio 1 handle 20 fw classid 1:20 tc filter add dev $DEV parent 1:0 protocol ip prio 1 handle 30 fw classid 1:30 # 2. 使用 iptables 给不同IP的流量打标记(mangle表) # 注意:数据包流向是 外网->eth0->Linux->eth1->内网。 # 我们控制的是从 eth1 发出去的数据,所以在 PREROUTING 或 FORWARD 链打标记。 # 这里使用 FORWARD 链,针对源IP打标记(因为对于内网口eth1,出方向数据包源IP是内网IP) # 清除旧标记 iptables -t mangle -F # 总经理 IP 标记为 10 iptables -t mangle -A FORWARD -s ${CEO_IP} -j MARK --set-mark 10 # 研发部 IP 标记为 20 iptables -t mangle -A FORWARD -s ${DEV_IP} -j MARK --set-mark 20 # 其他所有 IP 标记为 30 (这里是取反,排除上面两个IP) iptables -t mangle -A FORWARD -s 10.0.0.0/24 -m mark --mark 0 -j MARK --set-mark 30逻辑闭环:
当总经理上网时,数据包经过FORWARD链被打上mark 10,经过eth1出去时,tc filter看到mark 10,将其放入classid 1:10,享受80M保底带宽。
第四章:进阶优化——解决“小包延迟”与“突发流量”
4.1 调整队列长度(txqueuelen)
网卡默认队列长度(txqueuelen)通常是1000。对于高带宽环境,建议调整,以防缓存过多导致延迟。
ifconfig eth1 txqueuelen 5004.2 针对UDP(视频/语音)的优化
视频会议使用UDP,如果UDP没有限制,会挤占TCP的ACK包,导致网页卡顿。
在iptables中,我们可以用LENGTH模块限制UDP大包,但更优雅的做法是结合qdisc的prio。不过最简单的,我们可以给UDP包更高的优先级(通过修改mark优先级)。
思路延伸:iptables -t mangle -A FORWARD -p udp --dport 53 -j MARK --set-mark 10(DNS优先)。
4.3 验证与调试
脚本写完后,赋予执行权限并后台运行:
chmod +x /usr/local/bin/bandwidth_control.sh bash /usr/local/bin/bandwidth_control.sh查看规则是否生效:
tc -s qdisc show dev eth1(查看统计,看有没有丢包或Overlimits)tc -s class show dev eth1(查看各类的流量统计)
压力测试:
在内网找两台电脑,一台10.0.0.99(研发)开启迅雷下载,一台10.0.0.88(CEO)使用iperf3打流测试带宽。通过nload或iftop观察流量分配情况。
第五章:落地为服务——开机自启与异常监控
手动运行脚本不够专业,我们需要将其变为Systemd服务。
创建服务文件
/etc/systemd/system/traffic_control.service:
[Unit] Description=Bandwidth Control Service After=network.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/local/bin/bandwidth_control.sh ExecStop=/sbin/tc qdisc del dev eth1 root User=root [Install] WantedBy=multi-user.target启动并设置开机自启:
systemctl daemon-reload systemctl enable traffic_control.service systemctl start traffic_control.service第六章:避坑指南(大神忠告)
关于上行与下行:本文主要控制下行流量(针对内网口eth1的出口)。如果要控制上行(如限制内网上传视频到云端),需要控制外网口
eth0的出口,脚本逻辑同理,但需要调整网卡和IP方向(此时源IP变成了外网公网IP,标记需要改成-d目标IP匹配,比较复杂。一般企业更关注下行)。网卡Offload问题:部分高性能网卡(如Intel i350)开启了
GRO/GSO,会导致TC无法识别小包,产生Overlimit(超限)计数异常。建议关闭:ethtool -K eth1 gro off gso off tso off千万不要在虚拟机上测试:VMware/VirtualBox的虚拟网卡驱动对TC支持不友好,结果不具备参考意义,请在物理机或云宿主机(直接支持SR-IOV)上测试。
写在最后
很多人觉得Linux只能做服务器,实际上在网络领域,Linux内核的数据包处理能力远超同价位的硬件路由器。通过本文的HTB + iptables组合,你已经可以构建一个媲美中端企业级路由器的流控系统。
但这只是开始,如果你感兴趣,下一步可以研究:
Policy Routing(策略路由):双线接入,电信走电信,联通走联通。
Netfilter conntrack:连接跟踪优化,防止NAT表爆满。
如果你在部署中遇到RTNETLINK answers: No such file or directory等报错,请检查网卡名称是否正确,或modprobe sch_htb是否加载了HTB内核模块。
希望这篇实战能帮你搞定老板的“网速慢”抱怨。欢迎在评论区留下你的部署心得或踩坑记录。