服务器带宽被占用,教你限制进程网络速度
当服务器带宽被某个进程占满,网站打不开、SSH 卡顿,很多新手会直接重启或杀进程。
其实可以单独限制这个进程的网速,不影响其他服务。
下面用 Linux 自带的 tc 和 cgroup 来实现,无需额外软件。
先找出是谁占用了带宽
登录服务器,用 nethogs 或 iftop 按进程查看实时流量。
如果没安装,用包管理器装上:
# CentOS / Rocky Linux
yum install epel-release -y && yum install nethogs -y
# Ubuntu / Debian
apt install nethogs -y
运行 sudo nethogs,会列出每个进程的上传下载速度。
找到 PID 和进程名,比如一个 Java 进程 PID 为 12345。
记录下这个 PID。
用 cgroup 和 tc 对单个进程限速
核心思路:给目标进程创建独立的 cgroup,然后用 tc 对这个 cgroup 的流量做整形。
以下是完整操作(适用于 CentOS 7/8、Ubuntu 20.04+)。
1. 创建 cgroup 并绑定进程
# 创建 net_cls 组(路径示例)
sudo mkdir -p /sys/fs/cgroup/net_cls/limited
# 设置一个 classid,格式 0xAAAAABBB AAAA=主编号 BBB=子编号
echo 0x100001 > /sys/fs/cgroup/net_cls/limited/net_cls.classid
# 把进程 PID 写入 tasks(假设 PID=12345)
echo 12345 > /sys/fs/cgroup/net_cls/limited/tasks
注意:如果提示 Permission denied,加上 sudo 或用 root 执行。
cgroup 路径在部分系统可能是 /sys/fs/cgroup/net_cls 或 /sys/fs/cgroup/unified,以实际为准。
2. 用 tc 对 classid 限速
假设你想限制上传速度为 1Mbps(1024kbps),出网接口为 eth0:
# 先清除 eth0 上已有的 qdisc(如果有)
sudo tc qdisc del dev eth0 root 2>/dev/null
# 创建根句柄 1:,使用 htb 队列
tc qdisc add dev eth0 root handle 1: htb default 30
# 创建一个类,父类 1:,classid 1:1,速率 1mbit
tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit ceil 1mbit
# 把 cgroup classid(0x100001)映射到 tc 类
tc filter add dev eth0 parent 1: protocol ip prio 1 handle 1: cgroup
如果需要限制入站(下载)速度,入站限速较复杂,一般建议在交换机或对端限速。
出站限速对大多数场景已够用。
避坑指南
- classid 对应关系:cgroup 的
net_cls.classid值的写法是十六进制,而 tc filter 中handle 1:表示主编号 1,子编号不需要写。一定要确保 filter 的handle加上冒号和 cgroup 的 classid 主编号一致(都是 1)。 - tc 规则不持久:服务器重启后规则消失。可以把上述命令写成一个脚本,加入开机自启(如 systemd service)。
- 进程再产生的子进程:tasks 只包含当前写进去的 PID,子进程不会自动继承。如果进程频繁创建子进程(如 nginx worker),可以考虑限制整个用户或 docker 容器。
验证限速是否生效
- 重新运行
nethogs观察该进程的速度是否稳定在 1Mbps 附近。 - 用
tc -s class show dev eth0查看类 1:1 的发送速率的统计。 - 也可以手动模拟大流量测试:对这个进程触发大量上传(如用
scp上传文件),然后用iftop -i eth0观察。
如果发现速度没有限制,检查 net_cls.classid 是否正确写入,以及 filter 规则是否匹配。
也可以临时把 rate 改成极小的值(比如 10kbps)来快速验证变化。
高频问题
Q:限制下载速度怎么弄?
A:Linux 对入站流量的限制比较困难,因为数据包到达网卡后才做整形。建议在路由器或云服务商控制台按 IP 限速,或者使用 tc 的 ingress qdisc 但效果不稳定。
Q:我不想用 cgroup,能只限制 IP 吗?
A:可以。用 tc 直接对源 IP 或目的 IP 做 filter 限制,但会限制该 IP 所有进程,无法精确到单个进程。
Q:重启后规则没了怎么办?
A:建议写成 systemd unit 或写入 /etc/rc.local(需要可执行权限)。或者使用 tc qdisc add 命令集合放在一个脚本中。
如果按照上面的步骤操作,哪怕只接触过 Linux 基本命令,也能成功限制占用带宽的进程。
当服务器带宽再次被占满时,不用再慌张重启,先查哪个进程,再动手限速即可。