☰
Linux压测工具stress详解:CPU、内存、IO与磁盘加压实战
2026/10/10 6:42:50 网站建设 项目流程

简介:这是一份面向Linux系统管理员、运维工程师及开发者的stress压力测试工具源码包,用于模拟CPU、内存等系统资源的高负载,检测硬件在极端条件下的稳定性与性能极限,是评估服务器承载能力和排查高负载问题的常用手段。压缩包共32个文件,以C源码、configure构建脚本、Makefile.in及Makefile.am编译配置、texi/info/html文档和README说明为主,整体仅199KB,轻量紧凑,便于下载后在本机编译安装并快速开展压力测试。当前已有1036人学习下载。借助包内源码和配套文档,读者可以深入了解stress的参数定制方式,如设置线程数、内存分配大小和运行时长;同时结合top、vmstat等监控工具观察系统响应,判断CPU、内存的瓶颈所在。对于需要验证系统稳定性、调优内核参数或进行基准对比的技术人员,这份资源提供了简洁实用的参考实现与配置思路。

1. stress 不是玄学,是压测入门的第一把尺子

做运维和系统开发的人,大概率都遇到过这种场景:某台线上机器间歇性卡顿,top 一看 load average 飚到 30,业务方说没跑什么大任务;或者刚上线的服务一遇到促销流量 CPU 直接 100%,连 SSH 都敲不动。这时候如果手边没有一个趁手的加压测试工具,就只能靠“重启大法”和跟风猜原因。stress linux 加压测试工具就是解决这类问题的第一把尺子。它能用一条命令把 CPU、内存、IO、磁盘的压力稳定挤到指定水位,快速验证“这台机器到底能扛多久、瓶颈在哪”,比用真实业务去试探要安全得多。新手用来做稳定性验证,熟手用来提炼系统容量边界,只要你是在 Linux 环境下排查性能问题或验收设备,这个工具都值得先装进工具箱。

2. stress 加压原理与选型:它到底在压什么,怎么让它听话

2.1 stress 的核心机制:fork 子进程与系统调用轰炸

stress 本身是一个 C 语言写的小程序,它不搞复杂的负载模型,核心逻辑就是“fork 出大量子进程,每个子进程执行一个无脑循环”。CPU 子进程跑一个永远不退出的平方根运算循环,让算术逻辑单元和浮点单元满载;内存子进程不断调用 malloc 分配指定大小的内存块,再用 memset 把每一页真正“touch”一遍,触发缺页中断和伙伴系统分配;IO 子进程循环调用 sync 系统调用,迫使内核把脏页刷到磁盘;磁盘子进程则反复创建、写入、删除文件。

选择它而不是上来就上 fio 或 sysbench,原因是定位不一样。fio 的强项在磁盘队列深度和 IOPS 微调,但配置复杂,光 ioengine 和 rw 模式就够研究半天;sysbench 偏数据库事务和线程竞争模拟。而 stress 的“傻”恰恰是它的优势——压力均匀、无业务逻辑干扰、可预测性强。我用它做前期的“跌倒测试”特别合适:先快速判定系统在满载时是不是会立刻翻车,再决定要不要上重型工具深挖。它相当于体检时的量血压,虽然不能替代 CT,但能在三分钟内告诉你这台机器“有没有明显的心血管疾病”。

2.2 安装与最小验证:apt/yum 一行装好,先跑个 30 秒冒烟测试

在你的测试机上,安装 debian 系和 RHEL 系的命令略有不同,下面这段可以直接抄:

# debian / ubuntu 系 sudo apt-get update && sudo apt-get install -y stress # rhel / centos 7/8/9 系 sudo yum install -y stress # 或 dnf install -y epel-release && dnf install -y stress

装完先别着急上重负载,跑一个 30 秒的冒烟测试,确认它真的能起进程:

stress --cpu 2 --timeout 30s --verbose

参数说明:--cpu 2表示压两个 CPU 核心;--timeout 30s是 30 秒后自动退出,这个参数是保命符,后面所有命令我都建议带上;--verbose会让程序打印实时状态。执行后你应该能看到类似“successfully spawned”的提示,如果提示 fork 失败或权限拒绝,先检查是不是没装全依赖,或者处于容器环境中被 cgroup 限制住了。冒烟测试通过后,我们再往下看四大压力模式的具体调参。

3. 四大加压模式与参数设置:CPU、内存、IO、磁盘该怎么填

3.1 CPU 加压:烧核不是目的,背压和降频才是观察点

CPU 压测最常见的误解是把--cpu参数直接填成 CPU 线程数就万事大吉。实际上,stress 的 busy loop 并不怎么消耗内存带宽,它跑的是纯算术指令流。如果机器开了超线程,建议--cpu填物理核数,因为超线程的逻辑核在浮点单元上是共享的,填满反而容易让系统调度器产生不必要的争抢。

实战命令一般这么写:

# 查看物理核数 nproc --all # 压满全部物理核心,持续 10 分钟 stress --cpu 4 --timeout 600s --verbose

参数说明:--cpu 4是产生 4 个忙等进程;--timeout支持后缀 s、m、h。跑的时候要重点观察的其实不是 load average,而是 CPU 频率和核心温度。我的习惯是开两个窗口,一个跑 stress,另一个用mpstat -P ALL 1看每个核心的使用率,用watch -n 1 "cat /proc/cpuinfo | grep MHz"看频率有没有因为温度墙降到乞丐频率。如果发现频率掉得很厉害,说明散热已经成了瓶颈,这时候压测的目的就达到了——业务上遇到的 CPU 100% 导致响应慢,不一定是代码问题,很可能是散热背压导致降频,这个现象用 stress 能非常直观地复现出来。

3.2 内存加压:分配速度、锁页与 OOM 的边界

内存压测的坑比 CPU 多,核心原因是 malloc 是惰性分配。你不去 touch 内存页,内核就只是记账,实际物理内存根本没变化。stress 对内存的处理是分成分配、touch、保持三个阶段,用--vm-bytes指定总大小,内部再切块。

经典命令是这一条:

stress --vm 2 --vm-bytes 2G --vm-hang 30 --timeout 60s

参数说明:--vm 2表示启动两个子进程;--vm-bytes 2G说每个子进程分配 2GB 内存;--vm-hang 30让子进程在 touch 完所有页后保持 30 秒不释放,这样你才有时间去看内存监控数据;--timeout 60s兜底自动退出。跑的时候注意 free -m 里的 used 是否真的涨上去了,如果只是 allocated 高而 used 不动,那就是没触发缺页,需要调整--vm-stride(按多少字节跨步 touch)来强制逐页写入。我一般把--vm-stride设为 64 或 128,这个值对应一个 cacheline 的大小,能最大化缺页中断的频率。

内存压测的边界值别拍脑袋。如果机器物理内存是 8G,你设--vm-bytes 8G很可能直接触发 OOM killer。内存测试的目的是压满而不是压炸,给内核和现有进程留 1~2G 余量才算合理。关于 OOM 的具体翻车现场,我在第五章里细讲。

3.3 IO 与磁盘加压:写缓存和脏页回写对测试的影响

IO 压测很多人只是随便填个--io 4,结果发现磁盘 iostat 一点波澜都没有,就说 stress 垃圾。其实是理解有偏差。--io参数产生的是 sync 系统调用频率,它逼的是内核的脏页回写路径和块设备调度队列,直接观测点应该是iowait百分比,而不是磁盘吞吐。真要看磁盘吞吐,得用它配套的--hdd参数:

stress --hdd 2 --hdd-bytes 512M --timeout 120s

参数说明:--hdd 2产生两个子进程,各自创建一个临时文件并循环写入;--hdd-bytes 512M指定每次写文件的大小是 512MB;如果不指定输出目录,它默认写到当前工作目录的临时文件上。这里有个非常容易踩的坑:很多人的当前目录是/tmp,而/tmp在现代 systemd 机器上往往是 tmpfs(内存盘),结果你压测的是内存带宽,磁盘一点没动。所以我一般写死工作目录:cd /var/tmp && stress --hdd 2 --hdd-bytes 512M --timeout 120s,/var/tmp通常是真实磁盘分区。

跑起来之后看iostat -x 1里的%util和w_await才有效果。注意 IO 压测对 SSD 和机械硬盘的破坏性差异,机械硬盘长时间满负荷连续写会加速坏道产生,建议还是一次测试不要超过 300 秒,测出问题就收。毕竟我们是要验证系统的稳定性,不是给硬盘做极限耐久测试。

4. 写一个可持续的压力测试任务:脚本、监控与日志三件套

4.1 定制加压脚本:用 timeout 和循环控制时长与阶梯

单条 stress 命令适合快速测试,但做正式的容量验收,你需要一个能自动跑阶梯负载、留日志、结束能收尾的脚本。下面这个脚本是我常用的模板,抄下来改成你的参数就能用:

#!/bin/bash # 可持续压力测试脚本:先测 50% 负载,再测 100% 负载 LOG_DIR=/var/log/stress_test HOST_IP=$(hostname -I | awk '{print $1}') TEST_DATE=$(date +%Y%m%d_%H%M%S) LOG_FILE="${LOG_DIR}/stress_${HOST_IP}_${TEST_DATE}.log" mkdir -p "${LOG_DIR}" # 获取物理核心数 CORE_COUNT=$(nproc --all) STEP_COUNT=$((CORE_COUNT)) # 记录测试初始状态 echo "=== Stress Test Start ===" | tee -a "${LOG_FILE}" echo "$(uptime)" | tee -a "${LOG_FILE}" # 第一轮:50% 负载,持续 3 分钟 echo "[Step 1] 50% load - ${STEP_COUNT} cpu" | tee -a "${LOG_FILE}" stress --cpu $((STEP_COUNT / 2)) --vm 1 --vm-bytes 1G --timeout 180s >> "${LOG_FILE}" 2>&1 # 检查子进程是否暴毙 if [ $? -eq 0 ]; then echo "[Step 1] PASSED" | tee -a "${LOG_FILE}" else echo "[Step 1] FAILED - stress exit code: $?" | tee -a "${LOG_FILE}" exit 1 fi # 中间休息 10 秒,让系统把脏页刷完 sleep 10 # 第二轮:100% 负载,持续 5 分钟 echo "[Step 2] 100% load - ${STEP_COUNT} cpu" | tee -a "${LOG_FILE}" stress --cpu "${STEP_COUNT}" --io 2 --vm 2 --vm-bytes 2G --timeout 300s >> "${LOG_FILE}" 2>&1 if [ $? -eq 0 ]; then echo "[Step 2] PASSED" | tee -a "${LOG_FILE}" else echo "[Step 2] FAILED" | tee -a "${LOG_FILE}" exit 2 fi # 结束后收集系统状态 sleep 5 echo "$(uptime)" | tee -a "${LOG_FILE}" echo "=== Stress Test End ===" | tee -a "${LOG_FILE}"

脚本逻辑说明:STEP_COUNT取物理核数,第一轮压一半核心,第二轮压满并加上 IO 和内存的混合压力。tee -a同时输出屏幕和写日志,方便现场盯着也能事后翻记录。检查$?是为了捕获 stress 因信号被杀或 fork 失败的情况,如果中途挂了,日志里会明确记录是第几步失败的。注意--vm 2 --vm-bytes 2G这两项在第二轮是叠加的,意味着总共会申请 4G 内存,跑之前先free -g确认机器内存顶得住,别让脚本自己把机器 OOM 了。

4.2 监控配合:mpstat、pidstat 与 free 的读数校验

光有压测脚本没有监控等于考试没监考老师,翻车了都不知道是哪个瞬间崩的。压测时我习惯开四个独立的终端窗口,或者用 screen/tmux 分屏:

# 窗口一:看 CPU 各核使用率和软中断 mpstat -P ALL 2 # 窗口二:看 stress 子进程的详细状态和上下文切换 pidstat -u -p ALL 1 # 或者用 pidstat -d 1 看磁盘读写 # 窗口三:看内存和交换分区变化 free -h && watch -n 2 "grep -E 'Commit|MemTotal' /proc/meminfo" # 窗口四:看核心负载与进程队列 uptime && dmesg --follow

读数的逻辑要对应起来。如果mpstat显示所有核都 100% 且很平稳,但uptime的 load average 却低得离谱,大概率是 stress 子进程被 cgroup 限制;如果free里面的used在测试开始后几分钟一直缓缓增长,说明内存子进程正在触发持续的缺页和回收,这时候要去pidstat里找哪个进程的 minor fault 数值高。最关键的校验是:压测结束后,dmesg里不能出现 “Out of memory”,uptime的 load average 要在 1 分钟内回落到正常值。回落慢说明系统回收内存能力差,或者有进程被惊群效应拖住了。

5. stress 使用中的 5 个常见问题与排错:从翻车现场找原因

5.1 压测时 SSH 连不上,终端卡到无法输入

现象:执行stress --cpu 8后,自己所在的 SSH 会话开始无限卡顿,敲命令半天没反应,眼看就要 ssh 超时断开。 原因:压力过大时,系统调度器把绝大多数 CPU 时间片都分给了 stress 子进程,sshd 守护进程和你的 bash 会话得不到足够的 CPU 时间来处理网络中断和键盘输入。特别是在单核或 2 核的小机器上,这种情况几乎必然发生。 解决:一是永远给命令加--timeout,这是底线;二是压测时绝对不要直接在前台跑,要挂到后台或用nohup重定向输出;三是给 stress 绑核,用taskset -c 2,3 stress --cpu 2专门压物理核 2、3,留出零号核给系统进程,这样 SSH 始终有喘气的空间。如果你已经被卡死了,唯一后悔药就是等 timeout 到点,或者从另一个终端执行pkill -9 stress。

5.2 内存压测直接触发 OOM,系统看了几秒黑屏后自动重启

现象:跑了stress --vm 2 --vm-bytes 8G,刚过十几秒,终端里一行 “Out of memory” 日志飞过,随后本机所有进程卡死,ping 不通,过几分钟自动重启。 原因:内存参数拍脑袋设太大,Linux 内核的 OOM killer 开始批量牺牲进程,如果没有配置panic_on_oom,系统会因缺页异常引发内核 panic 进而重启。这是非常真实且高发的坑。 解决:压测前用free -m确认 MemAvailable 的真实值,--vm-bytes总和不要超过 Available 的 70%;更保险的做法是先用stress --vm 1 --vm-bytes 512M做小步递进,每次增加 256M,不断刷新观察水位,直到达到了想要的压力值就停下来。还有一招玄学:开启sysctl -w vm.overcommit_memory=2(不允许超额分配),让 malloc 在分配时直接失败而不是触发 OOM killer,这样 stress 自己会报错退出,系统不会崩。

5.3 磁盘 IO 压测时 iostat 统计几乎为零,白跑了

现象:执行stress --io 4 --timeout 60s,跑完看日志,iostat 的%util始终在 0,磁盘吞吐也没有变化,不知道压到哪儿去了。 原因:--io压的是 sync 系统调用的频率,它制造的是脏页回写队列压力,而不是直接的块设备读写流。在 page cache 充足的机器上,这种压力被缓存吸收了大半,磁盘自然波澜不惊。更隐蔽的原因是我前面提到的:stress 默认在当前目录创建临时文件,如果当前目录是 tmpfs,压力全在内存上。 解决:要压磁盘,必须改用--hdd参数,并显式cd /var/tmp或找一个真实挂载点作为工作目录。然后改用iostat -x 1观察w_await和%util,如果数值依然极低,检查文件系统是不是有延迟分配特性(比如 ext4 的delalloc),可以sync命令强制刷一下再对比一次。

5.4 压测日志显示 “fork failed: Cannot allocate memory”

现象:执行 stress 命令后,--verbose输出并没有出现 expected 的补充进程,而是直接报fork failed,随后退出。 原因:这个报错不是物理内存不足,而是系统资源达到了ulimit或 cgroup 的进程数限制(tasks limit),或者内存超额分配设置太保守导致 fork 时无法复制页表。我在容器里遇到过好几次,宿主机的核很多,但容器的pids.max限制为 512,而 stress 默认按--cpu数量 fork 子进程,一下子就撞墙了。 解决:先ulimit -u看当前最大用户进程数,确认没到阈值;再cat /sys/fs/cgroup/pids.max查看容器限制。如果你确实需要压很多核,只能减少--cpu N的值,或者给 stress 所在服务调高 pids.max 限制。知道这个坑,再遇到批量 fork 的压测工具(比如 sysbench 的 thread 模式),都知道先查进程数上限。

5.5 压测顺利结束,但之后业务服务反而启动失败或异常崩溃

现象:stress 命令带着--timeout正常跑完,exit code 是 0,机器没重启。但紧接着去启动应用,应用报数据库连接失败,或者内存分配异常。 原因:长时间满负载把某些依赖超时机制吹断了,比如 MySQL 在 CPU 100% 期间无法及时响应心跳,导致从库判断主库故障并切换;或者某些守护进程因内存压力被 OOM killer 记录在案,即使 stress 退了,系统的恢复和重试机制也需要时间,立刻启动新进程容易被旧状态绊倒。 解决:这不是 stress 的 bug,而是它暴露了你系统的高负载容错短板。压测结束后,我一般会在dmesg里查有没有 OOM killer 的日志,确认没有后才去启动业务;如果业务有 cluster 心跳机制,压测前先手动挂维护模式,别让业务方误判。压测的收尾动作要和压测本身同级别重视,不然就是测了个寂寞。

6. 进阶:用 stress-ng 细化压力模型,并验证测试结果有效性

6.1 stress-ng 的细粒度控制:按核、按线程、按调度策略

如果 stress 是初级的“大锤”,那 stress-ng 就是“瑞士军刀”。它是一个兼容 stress 语法但功能指数级扩展的加压工具,建议测试机上装一份:sudo apt install stress-ng。最常用的细化控制是用--cpu-method指定算法,比如stress-ng --cpu 0 --cpu-method fft会压所有核并跑快速傅里叶变换,而matrixprod则专门压矩阵乘法。这比 stress 的纯开方根循环更贴近科学计算场景。

我一般会在需要复现特定业务瓶颈时这么用:

stress-ng --cpu 4 --cpu-method matrixprod --vm 1 --vm-bytes 1G --vm-method malloc --io 2 --hdd 1 --hdd-bytes 1G --timeout 300s --metrics-brief

--cpu 0的 0 表示自动识别所有核;--vm-method malloc可以换成mmap去压页表分配;--metrics-brief会在退出时打印平均负载、退出原因等简洁指标。区别对比很清晰:stress 只能告诉我们“系统能不能压满”,stress-ng 能告诉我们“压满时执行哪种典型指令序列会导致更严重的性能坍塌”。

6.2 验证压测结果:看门狗与重启后的日志取证

压测跑完了,不能只看 exit code 是 0 就说稳定,得验证记录。我的习惯是把压测输出、dmesg 日志、监控截图打包归档。关键验证命令就三条:

# 检查内核日志里有无任何异常痕迹 dmesg | grep -iE "panic|oom|hung_task|soft lockup|hard lockup" | tail -20 # 检查压测进程是否全部干净退出,没有残留僵尸进程 ps -ef | grep stress | grep -v grep | wc -l # 重放一次短期的快速验证(例如 30 秒满载),对比前后的 load average 回落速度 stress --cpu 2 --timeout 30s && uptime

如果dmesg出现 “hung_task” 说明有进程 D 状态卡死;出现 “soft lockup” 说明某个核心长时间被中断风暴卡住。这些都是系统级故障的证据,拿着这些日志再去和内核、驱动厂商沟通,比空口说“机器不稳定”有说服力得多。用 systemd 的WatchdogSec服务也可以:压测期间如果系统偶发假死,看门狗会自动重启,重启后查看journalctl -b -1就能看到是被谁“踹”了。

最后想分享一个多年血泪经验:无论用 stress 还是 stress-ng,永远永远先加--timeout,哪怕是 60 秒也好,这是所有压测工具的第一个保命参数。我年轻的时候压一台没接显示器的机器,忘了加 timeout,结果 CPU 百分百发热,过了一晚直接热关机,第二天想复盘都没数据。记住,压测要压的是系统的边界,不是压你自己的项目工期。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询