1. 引言
在系统运维和性能测试中,模拟资源紧缺是验证系统在极端负载下行为的重要手段。本文介绍如何在 Linux 环境下使用 stress 命令模拟 CPU 和内存压力,使用 fallocate 模拟磁盘占用,并通过调整文件描述符上限来模拟 FD 资源紧缺,最后给出完整的验证与恢复方法。
2. 模拟 CPU 与内存压力
stress 是 Linux 下常用的压力测试工具,可以方便地模拟 CPU、内存、磁盘 I/O 等资源负载。安装方式如下:
bash
# CentOS / RHEL
yum install -y stress
Ubuntu / Debian
apt-get install -y stress
模拟 CPU 压力,启动 4 个 CPU 工作进程:
bash
stress --cpu 4 --timeout 60s
模拟内存压力,分配 2GB 内存并持续占用:
bash
stress --vm 2 --vm-bytes 2G --timeout 60s
也可以同时模拟 CPU 和内存压力:
bash
stress --cpu 4 --vm 2 --vm-bytes 1G --timeout 120s
3. 模拟磁盘占用
fallocate 可以快速预分配磁盘空间,用于模拟磁盘资源紧缺。例如创建一个 10GB 的临时文件:
bash
fallocate -l 10G /tmp/disk_test.bin
查看磁盘使用情况:
bash
df -h /tmp
测试完成后删除临时文件释放空间:
bash
rm -f /tmp/disk_test.bin
4. 模拟文件描述符资源紧缺
文件描述符(FD)是 Linux 系统中重要的资源,当进程打开的文件数接近系统上限时,会导致新的文件打开失败。下面演示如何模拟 FD 资源紧缺。
4.1 备份原始文件描述符上限
首先查看并备份系统当前的文件描述符上限:
bash
cat /proc/sys/fs/file-max
记录输出的原始值,例如 9223372036854775807,后续恢复时需要用到。
4.2 临时调低文件描述符上限
通过 sysctl 临时将系统文件描述符上限调低到 10000:
bash
sysctl -w fs.file-max=10000
4.3 运行消耗脚本
使用 Python 脚本打开约 9000 个文件描述符(目标为上限的 90%)。脚本内容如下:
python
import time
target = 9000
fds = []
for i in range(target):
try:
fds.append(open('/dev/null', 'r'))
except IOError:
break
if i % 1000 == 0:
time.sleep(0.01)
print 'Opened %d FDs' % len(fds)
time.sleep(6000)
在后台并行启动 7 个脚本来消耗文件描述符:
bash
for i in $(seq 1 7); do
python2 -c "import time
target = 9000
fds = []
for i in range(target):
try:
fds.append(open('/dev/null', 'r'))
except IOError:
break
if i % 1000 == 0:
time.sleep(0.01)
print 'Opened %d FDs' % len(fds)
time.sleep(6000)" &
done
4.4 验证文件描述符使用率
查看当前系统已分配的文件描述符数量:
bash
cat /proc/sys/fs/file-nr
该文件输出三个数值,分别表示已分配文件句柄数、已使用文件句柄数、文件句柄最大值。通过对比已分配数与上限值,可以确认文件描述符的使用率是否达到预期目标。
4.5 恢复文件描述符上限
测试完成后,将文件描述符上限恢复为原始值:
bash
sysctl -w fs.file-max=9223372036854775807
同时清理后台运行的 Python 脚本进程:
bash
pkill -f "python2 -c"
5. 模拟网络流量与连接资源紧缺
网络资源紧缺同样会影响系统稳定性。下面介绍使用 iperf3 模拟网络流量激增,并演示如何查看主机磁盘 IO 状态、网络延迟与丢包率,以及 TCP 连接数等关键指标。
5.1 使用 iperf3 模拟网络流量激增
iperf3 是常用的网络性能测试工具,可以生成大量 TCP/UDP 流量来模拟网络带宽压力。安装方式如下:
bash
# CentOS / RHEL
yum install -y iperf3
Ubuntu / Debian
apt-get install -y iperf3
在一台机器上启动服务端,监听默认端口 5201:
bash
iperf3 -s
在另一台机器上作为客户端,向服务端持续发送流量,模拟网络流量激增。例如持续 120 秒并开启 8 个并行连接:
bash
iperf3 -c 192.168.1.100 -t 120 -P 8
如需模拟 UDP 流量以观察丢包情况,可使用如下命令:
bash
iperf3 -c 192.168.1.100 -u -b 100M -t 120
5.2 模拟磁盘读写压力
用fio命令
安装 fio 的方法取决于你的系统。你之前用的是 CentOS/RHEL 系(yum),直接执行:
bash
sudo yum install fio -y
这就是 Oracle 官方文档里针对 CentOS 的标准安装命令。装完后可以用 fio --version 验证。
💡 补充说明
-
如果是 Ubuntu/Debian :命令是
sudo apt-get update && sudo apt-get install fio -y。 -
依赖库 :部分系统上 fio 可能依赖
libaio,如果启动时报错,可以补装sudo yum install libaio libaio-devel -y。
装好后,就可以用之前提到的多 job 命令来压满磁盘写入压力了。
fio 测试读写,写指定文件
搜索到 20 个网页
使用 fio 测试读写并指定文件,核心是通过 --filename 参数明确指定测试文件路径。
📝 基本语法
text
fio --name=任务名 --filename=文件路径 --rw=读写模式 --direct=1 --size=文件大小 --runtime=测试时长 --time_based
💡 关键参数说明
| 参数 | 说明 |
|---|---|
--filename |
指定测试文件路径。支持文件、裸盘,多个文件用冒号分隔,如 /dev/vda:/dev/vdb |
--rw |
读写模式:read(顺序读)、write(顺序写)、randread(随机读)、randwrite(随机写)、randrw(随机混合) |
--direct=1 |
绕过系统缓存,直接写入磁盘,测试更真实 |
--size |
测试文件大小,如 2G。若指定已有文件,size 可省略 |
--time_based |
配合 --runtime 使用,让 fio 在指定时间内持续运行,而不是写完文件就结束 |
--numjobs |
并发量 |
🧪 常用命令示例
顺序写测试
fio --name=write-test --filename=/root/fio_test.bin --rw=write --bs=10M --direct=1 --size=2G --numjobs=8 --time_based --runtime=6000
-
--numjobs=4:4 个并发写任务,压力更大 -
--group_reporting:汇总报告,方便查看整体性能
随机写测试
bash
fio --name=randwrite-test --filename=/root/fio_test.bin --rw=randwrite --bs=1M --direct=1 --size=2G --time_based --runtime=600
小块随机写更能压 IOPS。
混合读写测试
bash
fio --name=randrw-test --filename=/root/fio_test.bin --rw=randrw --rwmixread=70 --bs=4k --direct=1 --size=2G --time_based --runtime=600
--rwmixread=70:70% 读,30% 写
顺序读测试
fio --name=read-test --filename=/root/fio_test.bin --rw=read --bs=1M --direct=1 --size=2G --numjobs=4 --time_based --runtime=600 --group_reporting
⚠️ 注意事项
文件路径选择 :不要用 /tmp ,因为你的 /tmp 是 tmpfs(内存盘),测不出磁盘性能。建议用 /root/ 或专门的数据目录,确保是真实物理磁盘。
写测试会破坏数据 :如果对裸盘做写测试(如 --filename=/dev/vdb),会清空该设备上的所有数据,务必确认目标盘无有用数据。
--size 与已有文件 :如果指定的文件已存在且大小固定,--size 可省略;如果文件不存在,fio 会创建并填充到指定大小。
停止与清理 :--time_based --runtime=600 会在 600 秒后自动停止。测试完成后,生成的测试文件需要手动删除:
bash
rm -f /root/fio_test.bin
用 timeout 强制限时(最简洁)
timeout 命令可以让任意命令运行指定秒数后自动终止:
# 持续写 6000 秒
timeout 6000 dd if=/dev/zero of=/root/disk_io_test.bin bs=1M count=600000000 conv=fdatasync
# 持续读 6000 秒(绕过缓存)
timeout 6000 dd if=/root/disk_io_test.bin of=/dev/null bs=1M iflag=direct
注意:count 要设得足够大(比如 100000),否则 dd 会在 600 秒之前就写完退出,timeout 就失去意义了。上面的 count=100000 意味着最多写 100000MB,实际会被 timeout 在 600 秒时截断。
用 while 循环控制时长(更灵活)
bash
# 持续写 600 秒
bash
end=$((SECONDS+600))
while [ $SECONDS -lt $end ]; do
dd if=/dev/zero of=/root/disk_io_test.bin bs=1M count=2048 conv=fdatasync
done
# 持续读 600 秒
bash
end=$((SECONDS+600))
while [ $SECONDS -lt $end ]; do
dd if=/root/disk_io_test.bin of=/dev/null bs=1M iflag=direct
done
同时压读和写(并行)
如果你想同时制造读、写压力,可以把两个循环放到后台并行:
bash
# 先准备一个文件供读取(如果还没有)
dd if=/dev/zero of=/root/disk_io_test.bin bs=1M count=2048 conv=fdatasync
# 写压力
end=$((SECONDS+600))
while [ $SECONDS -lt $end ]; do
dd if=/dev/zero of=/root/disk_io_test_write.bin bs=1M count=2048 conv=fdatasync
done &
# 读压力
end=$((SECONDS+600))
while [ $SECONDS -lt $end ]; do
dd if=/root/disk_io_test.bin of=/dev/null bs=1M iflag=direct
done &
wait
关键参数说明
| 参数 | 作用 |
|---|---|
if=/dev/zero |
无限零数据源,用于写测试 |
of=/dev/null |
黑洞,读出的数据丢弃,用于读测试 |
bs=1M |
每次读写 1MB |
count=N |
读写 N 个块(总大小 = bs × count) |
conv=fdatasync |
写完后强制刷盘,确保真实写入物理磁盘 |
iflag=direct |
读时绕过 page cache,直接读物理磁盘 |
bash
stress -d 4 --hdd-bytes 1G -t 600
在压测期间,可以使用 iostat 观察磁盘 IO 是否成为瓶颈。安装 sysstat 后执行:
bash
# CentOS / RHEL
yum install -y sysstat
Ubuntu / Debian
apt-get install -y sysstat
每隔 2 秒刷新一次磁盘 IO 状态,共输出 5 次:
bash
iostat -x 2 5
重点关注 %util(设备利用率)、await(平均 IO 等待时间)和 r/s、w/s(每秒读写次数)等指标,判断磁盘是否处于高负载状态。
5.3 模拟网络延迟与丢包
iptable方式
# 模拟本机发出的包,随机丢弃 5%
sudo iptables -A OUTPUT -m statistic --mode random --probability 0.05 -j DROP
# 模拟发往本机的包(入向),随机丢弃 5%
sudo iptables -A INPUT -m statistic --mode random --probability 0.05 -j DROP
针对特定源 IP 丢包(入向)
bash
# 丢弃来自 10.11.55.83 的包,概率 5%
sudo iptables -A INPUT -s 10.11.55.83 -m statistic --mode random --probability 0.05 -j DROP
针对特定目标 IP 丢包(出向)
bash
# 丢弃发往 10.11.55.83 的包,概率 5%
sudo iptables -A OUTPUT -d 10.11.55.83 -m statistic --mode random --probability 0.05 -j DROP
tc方式
查询网卡
bash
ip -br link
所有网络
针对 ens3 模拟延迟和丢包
模拟 200ms 延迟 + 5% 丢包:(建议指定某个ip的流量或者指定过期时间)
sudo tc qdisc add dev ens3 root netem delay 200ms loss 5%
加规则,并让它在 300 秒(5 分钟)后自动删除
sudo tc qdisc add dev ens3 root netem delay 200ms loss 5% && (sleep 300 && sudo tc qdisc del dev ens3 root) &
命令解释:
-
&&:规则添加成功后,才启动后面的定时任务。 -
(sleep 300 && ...):子 shell 里先睡 300 秒,醒来后执行删除。 -
末尾
&:把整个定时任务放到后台,不阻塞当前终端。
这样即使你 SSH 断了,5 分钟后网络也会自动恢复。
指定固定ip丢包
如果只想影响访问某个 IP 的流量,而不是全部,可以结合 filter:
只对目标 IP 10.11.55.83 生效
bash
sudo tc qdisc add dev ens3 root handle 1: prio && \
(sleep 300 && sudo tc qdisc del dev ens3 root) & \
sudo tc qdisc add dev ens3 parent 1:1 handle 10: netem delay 200ms loss 5% && \
(sleep 300 && sudo tc qdisc del dev ens3 root) & \
sudo tc filter add dev ens3 protocol ip parent 1:0 prio 1 u32 match ip dst 10.11.55.83 flowid 1:1 && \
(sleep 300 && sudo tc qdisc del dev ens3 root) &
或者
bash
sudo tc qdisc add dev ens3 root handle 1: prio && \
sudo tc qdisc add dev ens3 parent 1:1 handle 10: netem delay 200ms loss 5% && \
sudo tc filter add dev ens3 protocol ip parent 1:0 prio 1 u32 match ip dst 10.11.55.83 flowid 1:1 && \
(sleep 300 && sudo tc qdisc del dev ens3 root) &
查看已添加的规则:
bash
tc qdisc show dev ens3
恢复(清除规则):
bash
sudo tc qdisc del dev ens3 root
5.4 模拟 TCP 连接数激增
使用 hping3 可以快速建立大量 TCP 连接,用于模拟高并发连接场景。安装方式如下:
bash
# CentOS / RHEL
yum install -y hping3
Ubuntu / Debian
apt-get install -y hping3
向目标主机持续发起 SYN 请求,模拟大量半开连接:
bash
hping3 -S -p 80 --flood 192.168.1.100
如需模拟大量完整 TCP 连接,可结合 iperf3 开启多个并行连接:
bash
iperf3 -c 192.168.1.100 -t 120 -P 8
在压测期间,可以使用 ss 命令查看当前系统的 TCP 连接状态和数量。统计所有 TCP 连接数:
bash
ss -s
查看处于 ESTABLISHED 状态的连接数:
bash
ss -t state established | wc -l
也可以按连接状态分类统计,观察 SYN-SENT、TIME-WAIT 等状态的连接数量:
bash
ss -tan | awk '{print $1}' | sort | uniq -c
在压测期间,TCP 连接数和各状态数量会明显上升,可用于验证系统在高并发连接下的表现。
5.5 恢复与清理
测试完成后,停止 iperf3 和 hping3 进程:
bash
pkill -f iperf3
pkill -f hping3
移除网络延迟和丢包模拟规则:
bash
tc qdisc del dev eth0 root
确认网络流量恢复正常,延迟和丢包率回到基线水平,TCP 连接数回落。
5.3 查看网络延迟与丢包率
使用 ping 命令可以快速查看网络延迟和丢包率。持续发送 100 个数据包并统计结果:
bash
ping -c 100 192.168.1.100
输出中的 time 字段表示往返延迟,packet loss 字段表示丢包率。在 iperf3 压测期间执行 ping,可以对比观察网络拥塞对延迟和丢包的影响。
5.4 查看 TCP 连接数
使用 ss 命令可以查看当前系统的 TCP 连接状态和数量。统计所有 TCP 连接数:
bash
ss -s
查看处于 ESTABLISHED 状态的连接数:
bash
ss -t state established | wc -l
也可以按连接状态分类统计,观察 SYN-SENT、TIME-WAIT 等状态的连接数量:
bash
ss -tan | awk '{print $1}' | sort | uniq -c
在 iperf3 压测期间,TCP 连接数和各状态数量会明显上升,可用于验证系统在高并发连接下的表现。
5.5 恢复与清理
测试完成后,停止 iperf3 服务端和客户端进程:
bash
pkill -f iperf3
确认网络流量恢复正常,延迟和丢包率回到基线水平,TCP 连接数回落。
5. 总结
本文介绍了在 Linux 环境下模拟资源紧缺的完整方法:使用 stress 模拟 CPU 和内存压力,使用 fallocate 模拟磁盘占用,通过临时调低 fs.file-max 并运行 Python 脚本模拟文件描述符资源紧缺。这些方法可以帮助运维人员验证系统在资源受限情况下的行为,为容量规划和故障演练提供依据。测试完成后务必恢复原始配置,避免影响生产环境。