简介:Linux压力测试工具stress是经典的开源系统稳定性与性能评估工具,此压缩包为stress-1.0.1完整源码,面向系统管理员、开发人员与测试人员,用于模拟中央处理器计算、内存分配、输入输出读写以及大量线程与进程并发,帮助查找系统瓶颈与资源管理缺陷。资源包体积仅199KB,共包含32个文件,类型覆盖C语言源代码、自动构建脚本、配置脚本、Texinfo帮助文档、HTML说明、自述文件、安装指南、变更记录与版权声明等,结构标准完整,可直接在Linux下编译安装或阅读研究。目前已有3089人学习下载,适合希望掌握压力测试原理、熟练使用stress各类参数并扩展自定义场景的技术人员。通过阅读源码可深入理解工具的实现方式,结合内置文档能快速上手,并将其应用于服务器稳定性验证、容量规划与性能优化实践。
1. linux压力测试工具stress:它测的不是性能,而是系统极限下的稳定性
第一次用 stress 的人,多半会误以为它是类似 Apache Bench 的性能测试工具,能测出「每秒处理多少请求」。但实际跑一遍就会发现,它不产生任何业务指标,只是老老实实地把 CPU、内存、I/O 拉到高负载,然后观察系统扛不扛得住。这正是它的定位:一个系统稳定性验证工具,而不是性能基准工具。它的典型场景是服务器上线前验收、超频或散热改造后的稳定性检查、嵌入式设备的长时间运行测试,甚至排查那些「重启就好但过几天又犯」的间歇性故障。一个反直觉结论是:stress 跑挂机器不一定是坏事,反而能提前暴露电源、风扇、内存接触这类平时发现不了的问题。下面把 stress 的安装、参数、实战方案和常见坑一次讲清楚。
2. 从安装到跑通第一个完整压测:stress 的获取、编译与最小命令
stress 的命令行设计非常朴素,一半时间花在选参数上,另一半时间花在确认负载真正生效。这一章先从安装讲起,然后通过一个最小的 CPU 压测命令把核心参数串起来,最后介绍压测过程中一定要上手看的三件套工具。读完你应该能在 5 分钟内跑出第一个有可信度的压测。
2.1 三种安装方式:包管理器最快,源码编译适合离线环境
常见的安装方式是通过发行版自带的包管理器。Debian 系执行apt install stress,RHEL 系执行yum install stress,Arch 系执行pacman -S stress。这种方式的优点是快,仓库里已经有编译好的二进制,缺点是版本往往比较旧,部分发行版还在用 1.0.4 或者 1.0.5。不过 stress 本身功能不复杂,除了 I/O 相关参数在不同版本间略有差异,日常使用影响不大。装完之后我建议立刻执行一遍stress --version和stress --help,确认命令可用,顺便把当前版本的参数列表记下来。
如果你在离线内网环境,或者想自己打一个静态版本放进最小化系统,源码编译是第一选择。stress 的依赖只有 libc,源码包解压后一条命令链就能编完:
tar -xf stress-1.0.x.tar.gz cd stress-1.0.x ./configure --prefix=/usr/local make -j4 sudo make install这段命令里,--prefix指定安装路径,默认装到/usr/local/bin。编译时如果提示缺少 configure 脚本,说明源码包不完整或需要重新生成,先执行autoreconf -if再 configure。还可以在 configure 前设置CFLAGS="-O2 -march=native"让 stress 针对当前 CPU 做优化,但这样编译出来的二进制只在相同 CPU 上稳定运行,所以我只在目标机器上直接编译,不跨机器拷。如果目标机上连 autoconf 都没装,优先选包管理器,或者在有网络的机器上编好静态版本带过去。
还有第三种方式是拉容器镜像跑。我不推荐用容器做系统级压测,因为容器隔离和虚拟化层会稀释真实硬件负载,尤其验证散热和电源稳定性时,容器里的负载映射到宿主机会有明显偏差。容器方式适合快速熟悉参数,不适合作为验收结论。前面几种方式,选包管理器或源码编译足够。
2.2 第一个 CPU 满载压测:最小命令加参数逐项拆解
装好以后,先跑一个最简单的命令,让 4 个 CPU worker 满载 60 秒:
stress --cpu 4 --timeout 60s --verbose--cpu 4会让 stress fork 出 4 个子进程,每个子进程内部不断执行平方根运算,持续占据一个逻辑核心。--timeout 60s让压测在 60 秒后自动结束,这个参数非常重要,因为 stress 默认会无限期运行,不设 timeout 的话测试完还要手动 kill。--verbose让每个 worker 的 fork 和退出信息都打到终端,方便确认压测确实启动。
stress 的全局参数不算多,我把常用的整理成一份速查表:
| 参数 | 全称 | 作用 |
|---|---|---|
-c N | --cpu N | 启动 N 个 CPU 密集型 worker |
-m N | --vm N | 启动 N 个内存分配 worker,配合--vm-bytes |
-i N | --io N | 启动 N 个执行 sync 调用的 IO worker |
-d N | --hdd N | 启动 N 个读写临时文件的磁盘 worker |
-t | --timeout | 指定压测时长,支持s、m、h后缀 |
-v | --verbose | 输出详细日志 |
-q | --quiet | 安静模式,只显示最终结果 |
-b | --backoff | worker 启动前休眠指定微秒数,避免 fork 风暴 |
我一般习惯在压测命令里同时写--verbose和--timeout,这样日志里能明确看到每个 worker 的起止时间,后续排查时对得上时间线。--backoff这个参数平时容易被忽略,但它在大规模压测时很有用,比如stress --cpu 32 --backoff 100000,让 32 个 worker 分批次启动,避免同一瞬间 fork 进程过多导致系统短暂卡死。
2.3 确认负载真实生效:top、mpstat、vmstat 三件套
压测不能光把命令丢进终端,你要能确认负载真正落在硬件上。最直接的观察是top,进入交互界面后按数字键1展开每个核心的使用率,正常情况下所有目标核心都应接近 100%。但top刷新频率有限,想看更细的调度情况,可以用mpstat -P ALL 1每秒打印一次每个 CPU 的用户态占比。
vmstat 1 5则能看到系统级的运行队列和用户态时间占比。重点关注r列,也就是运行队列中的进程数。当stress --cpu 4跑满时,r通常在 4 到 8 之间浮动;如果r值远高于 CPU 核心数,说明负载已经产生排队,系统出现调度延迟。这在组合压测中尤其需要关注,因为排队等待是系统失稳的前兆。
除了这三个工具,我还会再开一个终端盯着uptime,观察 load average 是否跟着波动。注意 load average 在压测结束时不会立刻归零,它是一段时间的平均值,要等几个采样周期才会回落,不要因为压测结束负载还很高就误以为系统出了问题。如果跑的是长时间压测,还可以用turbostat --quiet --show Core,CPU,MHz观察频率变化。
对 CPU 负载验证,还有一个反直觉的细节:当 worker 数量恰好等于逻辑核心数时,vmstat的us列会接近 100%,wa列是 0。如果你看到wa明显有值,说明 CPU worker 在等待 I/O,原因多半是内存或磁盘参数拖慢,这类现象要在组合压测时特别留意。以上三个工具看的是瞬时状态,如果做一小时以上的压测,我还会用脚本把这些数据落盘,到分析时直接看趋势,这部分会在第 4 章展开。
3. 参数决定负载模型:CPU、内存、I/O 与磁盘压测的正确姿势
3.1 CPU 压测:worker 数量怎么定,超线程要不要算进去
--cpu的数量直接决定你压的是哪个层面。如果只是想让所有物理核心满载,worker 数等于物理核心数即可;如果是验证极限散热,我一般会按逻辑线程数来设置。逻辑线程数可以通过lscpu里的CPU(s)查看,比如一台物理核心 8 核、超线程后 16 线程的机器,stress --cpu 16会把所有逻辑核心打满,发热量最接近真实重负载场景。
但这里有个容易踩的误区:stress --cpu 8并不是指定用 8 号核心,而是产生 8 个 CPU 密集型进程,操作系统会在所有核心间调度它们。如果你只看到部分核心满载,另一个常见原因是内核的负载均衡策略没及时迁移进程。想让负载严格固定在几个核心上,配合taskset是更可靠的方案:
taskset -c 0-7 stress --cpu 8 --timeout 300s --verbosetaskset -c 0-7把 stress 的 8 个 worker 全部限定在 0 到 7 号核心上。这套组合在做 CPU 隔离验证时非常实用,比如 NUMA 架构下单独验证某个节点的计算稳定性。默认情况下 stress 不会帮你绑核,所以遇到负载分布不均匀,先检查是不是没绑核,不要急着怀疑 CPU 个数设置错了。
3.2 内存压测:--vm-bytes 和 --vm-hang 决定负载特征
内存负载比 CPU 负载复杂,因为「压力」不只是占用多少空间,还包括分配、释放的频率。stress 的内存 worker 会反复执行「分配指定大小内存、填充数据、等待一段时间、释放、再分配」这个循环。最基本的压测命令是:
stress --vm 2 --vm-bytes 1G --vm-hang 5 --timeout 60s--vm 2表示启动 2 个内存 worker,--vm-bytes 1G是每个 worker 单次分配的大小,--vm-hang 5表示分配后挂起 5 秒再释放。这个--vm-hang参数很关键,它决定内存压力是「脉冲式」还是「持续式」。--vm-hang 0时每个 worker 分配完立刻释放,产生频繁的分配释放压力,对内存分配器和缺页异常路径的压力更大;把--vm-hang设成 60 这类较大的值,能更长时间维持高内存占用,模拟「内存被大量业务进程长期占用」的场景。
设置--vm-bytes时一定要先看物理内存大小。总内存 16G 的机器如果配--vm 4 --vm-bytes 8G,总占用会达到 32G,远超物理内存,系统会立刻进入 swap,甚至触发 OOM Killer。我更推荐按总内存的 80% 来估算,例如 16G 内存跑 2 个 worker,每个 worker 的--vm-bytes不要超过 6G。更稳妥的做法是先执行free -g查看 Available 值,减去系统本身的内存余量,再决定参数。
3.3 I/O 与磁盘压测:--io 的 sync 调用和 --hdd 的读写循环
I/O 压测有两类参数,--io和--hdd,负载性质完全不同。--io N让 N 个 worker 不断执行sync()系统调用,这个调用会请求内核把脏页刷回磁盘,所以它对整个块设备子系统产生全局性压力。实际跑起来你会发现,--io的负载在iostat上体现为较高的await,但磁盘吞吐不一定高,因为 sync 触发的是写回队列的抖动。
--hdd N产生的是真实的磁盘读写:每个 worker 创建一个临时文件,先写--hdd-bytes大小的数据,再随机读取和重写,测试结束后会删除临时文件。一个常用命令是:
stress --hdd 4 --hdd-bytes 2G --timeout 120s --verbose这里 4 个 worker 各自写 2G 临时文件,总写入量 8G。跑之前务必确认当前目录所在磁盘有足够空间,最好把工作目录放到独立的裸盘挂载点。常见的翻车是把 stress 跑在根分区,--hdd-bytes没算好,直接把根分区写满,系统日志都刷不出来。另外要注意版本差异,个别旧版 stress 的--hdd测试完不会自动清理临时文件,跑完要手动检查目录下有没有stress.*残留文件。
3.4 组合压测:CPU、内存、I/O 同时压时系统会发生什么
真实业务负载很少是单一资源占满,所以验收时我更倾向于把多种负载组合起来。组合压测的一个典型命令如下:
stress --cpu 4 --vm 2 --vm-bytes 512M --io 2 --hdd 1 --hdd-bytes 1G --timeout 300s这条命令会创建 4 个 CPU worker、2 个内存 worker、2 个 sync worker 和 1 个磁盘 worker,互相叠加。组合压测最值得观察的有两个点:第一,系统在多种负载抢资源时是否出现明显的调度延迟,可以对照mpstat里的%steal列和vmstat的r列;第二,是否出现内存紧张导致的抖动,因为 CPU worker 和磁盘 worker 本身也吃内存,再加上--vm的分配,会更快逼近物理内存上限。
组合压测的另一个用途是复现间歇性疑难问题。比如某台服务器在业务高峰时偶尔出现卡死,单独压 CPU 没问题,单独压内存也没问题,组合压十几分钟后问题就复现。这类问题只有组合负载才能逼出来,所以不要把组合压测当成简单的「一起跑」,它本身就是一种相关性测试手段。
4. 系统稳定性验收实战:从 10 分钟到 24 小时的完整压测方案
4.1 压测时长怎么选:10 分钟、1 小时、24 小时分别验证什么
压力测试不是跑得越久越有效,时长要和验证目标匹配。10 分钟级别的压测适合快速冒烟,比如刚装完系统、改过内核参数后,确认机器还能稳定运行,典型场景是调试阶段反复修改配置时做回归检查。1 小时级别是上线前验收的最低门槛,能覆盖大部分散热问题和调度异常,大多数周期性温度波动在 1 小时内会显现出来。
24 小时级别的压测属于出厂老化测试级别,主要面向 7x24 小时运行的设备或不打算频繁维护的服务器。这个量级下,重点已经不是「能不能跑」,而是内存位翻转、磁盘错误、RAS 事件这类低频硬件故障。我见过团队把 stress 当作老化测试脚本的一部分,整机生产流程里跑满 48 小时,任何一次 dmesg 报错都会判定为不合格。三种时长的定位可以参考下面的表:
| 压测时长 | 重点验证内容 | 适合场景 |
|---|---|---|
| 10 分钟 | 基本资源加载、散热初步验证 | 开发自测、调试回归 |
| 1 小时 | 散热曲线、调度稳定性、间歇问题 | 服务器上线前验收 |
| 24 小时及以上 | 硬件老化、内存位翻转、RAS 错误 | 设备出厂、无人值守部署 |
注意,长时间压测一定要设--timeout,避免压测进程无人看管时无限跑下去。如果确实需要不定长压测,可以用nohup或系统守护进程挂后台,但更推荐在命令行里直接写清时长,便于第二天回来还能对上时间线。
4.2 压测期间收集什么数据:温度、频率、内存错误、系统日志
压测跑起来以后,你真正要看的是四类数据。第一是温度,cat /sys/class/thermal/thermal_zone*/temp可以拿到各个温度传感器读数,单位是千分之一摄氏度,读出 85000 表示 85 度。第二是频率,grep MHz /proc/cpuinfo能实时看到每个核心当前频率,如果热量大到降频,这里会明显低于标称值。
第三是内存错误,主要看dmesg -T中有没有Hardware Error、EDAC或Memory Parity关键字。第四是系统日志,建议压测期间持续观察journalctl --since "10 minutes ago",尤其关注unexpected reboot、watchdog、call trace这些词。温度、频率这类数据要定期记录,不能只在结束时刻看一次,下面这段脚本会把采样写入 CSV:
LOG_DIR=/var/log/stress-test mkdir -p "$LOG_DIR" echo "time,zone,millidegree_celsius,mhz" > "$LOG_DIR/thermal.csv" while true; do temp=$(cat /sys/class/thermal/thermal_zone*/temp | tr '\n' ',') freq=$(grep -m1 "MHz" /proc/cpuinfo | awk '{print $4}') echo "$(date +%FT%T),${temp}${freq}" >> "$LOG_DIR/thermal.csv" sleep 5 done这个循环每 5 秒采样一次。tr '\n' ','把多个温度传感器的读数拼成一串,方便后续导入表格分析。grep -m1 "MHz"只取第一个核心的频率,如果要记录所有核心,把-m1去掉即可。这样积累的数据能直接看出压测过程中频率有没有持续下滑,如果温度还在涨但频率已经掉了很多,说明散热余量不足,机器在临界边缘。
4.3 一键验收脚本:压测、监控、日志和结果判断整合成一条命令
分开开终端跑 stress 再采集数据,很容易漏采或者忘记保存日志。我习惯写一个验收脚本,把 stress 拉到后台、循环采样、结束后检查日志和退出码,整合成一条命令。下面是一个精简但完整的版本:
#!/bin/bash DURATION=${DURATION:-3600} STRESS_CMD="stress --cpu 8 --vm 2 --vm-bytes 1G --timeout ${DURATION}s --verbose" LOG_DIR=/var/log/stress-test mkdir -p "$LOG_DIR" $STRESS_CMD > "$LOG_DIR/stress.out" 2>&1 & STRESS_PID=$! while kill -0 "$STRESS_PID" 2>/dev/null; do echo "$(date +%FT%T) load=$(cut -d' ' -f1 /proc/loadavg)" >> "$LOG_DIR/load.log" sleep 10 done wait "$STRESS_PID" RC=$? dmesg -T > "$LOG_DIR/dmesg-after-test.log" if grep -qEi "oom|hardware error|soft lockup|call trace" "$LOG_DIR/dmesg-after-test.log"; then echo "FAIL: 检测到异常内核日志" exit 1 fi if [ "$RC" -eq 0 ]; then echo "PASS: stress 正常退出" else echo "FAIL: stress 退出码 $RC" fi脚本里,$STRESS_CMD放到后台执行,kill -0 "$STRESS_PID"用来判断 stress 进程是否还活着,循环里每 10 秒记录一次 load average。stress 结束后,dmesg -T把内核环形缓冲导出,再 grep 几个典型的异常关键字。需要特别解释的是wait "$STRESS_PID"的退出码:只有 stress 进程自己正常退出时它才是 0,如果进程是被外部 kill 掉或者崩溃退出,退出码会变成非 0,正好用来捕捉「压测中途挂了」这种情况。注意脚本需要在 root 权限下运行,否则dmesg会被内核限制权限,读不到完整日志。
这个脚本还能继续扩展,比如压测期间通过带外管理工具记录硬件传感器,或者在压测结束后分析thermal.csv里的温度峰值是否超过阈值。目标就是让压测结果判断不依赖人工盯屏,而是靠日志和退出码说话。这样即使半夜跑出来的结果,第二天早上也能直接看到 PASS 或 FAIL。
5. stress 避坑指南:5 个常见的翻车现场与排查思路
5.1 现象:压测还没到一半,SSH 突然断连,系统失去响应
压测开始几分钟后,终端卡住,SSH 连不上,ping 能通但登录不了。这种情况大多出现在--cpu设置过高的场景,比如 8 核机器直接--cpu 32,或者同时叠加了--vm和--hdd后总负载超过系统能处理的范围。当运行队列里的任务数远高于核心数时,内核处理时钟中断和网络软中断的时间被大量挤占,SSH 服务得不到调度,表现就是「假死」。
解决的关键是先给自己留条后路。压测前用taskset -c 0-3 stress --cpu 16把负载限制在部分核心上,保留几个核心给系统管理;或者用--backoff参数错开 worker 启动时间,避免瞬间 fork 太多进程。如果已经卡死,不要急着按电源键重启,先等几分钟让负载自动缓解,或者通过带外管理口执行killall stress。另外建议压测时始终带--timeout,就算眼前卡了,进程到点也会自己退掉。
5.2 现象:压测进行中,stress 进程不见了,dmesg 出现 OOM Killer
内存压测跑着跑着,stress 进程大量消失,命令行返回Killed。检查dmesg,能看到Out of memory: Killed process记录。原因非常直接:--vm-bytes乘以 worker 数量后,再加上系统本身占用的内存,超过了物理内存和 swap 的总和。这是内存压测最容易踩的坑,而且一旦触发 OOM,系统会随机挑选进程杀掉,可能误伤正在运行的其他服务。
解决方法是先算清楚预算。用free -h看 Available,再决定 worker 数和单个内存大小。比如 Available 只有 12G,--vm 4 --vm-bytes 4G就已经踩线了,我会把总目标占用控制在 Available 的 70% 到 80%。如果确实想测试 OOM Killer 的行为,不要用 stress 硬触发,它有更合适的替代品,比如 stress-ng 的--vm-oom,可以控制触发时机,好过让系统随机杀进程。
5.3 现象:CPU 使用率 100% 但频率只有 1.2GHz,性能远低于预期
压测后看top,所有核心都是 100%,但程序实际推进速度很慢。用grep MHz /proc/cpuinfo一看,频率已经降到了基础频率甚至更低。这个现象在笔记本和小型工控机上尤其常见,原因也很明确:压测产生的热量让 CPU 触及温度墙,触发了降频。stress 在这里的角色是「诱因」,不是「故障」,它把散热短板从看不见的地方拉到了台面上。
处理方向分两层。第一,先确认散热:清理风扇灰尘、重新涂硅脂、调整风扇策略,再重新压一遍看频率曲线。第二,如果需要的是性能测试,不要用默认的 CPU worker,因为默认的平方根运算不一定能让 CPU 达到最高功耗,换成 stress-ng 的matrixprod这类密集计算更有效。频率下降未必是坏事,它本身也是监控数据的价值所在,能告诉你散热余量到底还剩多少。
5.4 现象:磁盘压测时,正在跑的业务服务 IO 延迟飙升
一台服务器上同时跑着业务,你只想压一下磁盘,结果业务方反馈服务变卡了。查看iostat -x 1,%util可能并不高,但await明显上升。原因有两类:一个是--io的sync()调用会反复触发全局脏页刷盘,影响整个块设备;另一个是--hdd的多个 worker 在同一个磁盘上争抢队列,导致排队延迟变高。
解决思路是隔离和降优先级。压测前确认没有关键业务在同一个物理磁盘上,尽量把压测放到独立盘;必要时用ionice -c 2 -n 7 stress --hdd ...把 stress 的 IO 优先级降到低,让业务 IO 优先。另外要认真设置--hdd-bytes,避免写入量过大耗尽磁盘空间。生产环境里我的原则是:压测试验机,业务机上只做短时低强度验证,不为了数据好看去影响现网。
5.5 现象:同一个命令在不同机器上表现不一样,甚至参数直接报错
从 A 机器拷贝的压测命令,在 B 机器上执行时报unrecognized option,或者跑起来行为不一致。这多半是 stress 版本不一致造成的。比如旧版本对--hdd-bytes的默认值有过调整,个别编译版本没有--backoff,不同发行版打的补丁也可能改变参数语义。这类问题属于典型的版本玄学,靠搜关键词往往找不到答案,最有效的办法是看本机帮助。
解决的方法很朴素:先stress --version看版本,再stress --help确认当前版本的参数表。如果对版本差异不放心,直接改用 stress-ng,它的参数命名更统一,遇到不支持的选项会明确报错,而不是悄悄改变行为。不要凭记忆里的命令在陌生环境直接跑,先帮助、后运行,能省掉很多无意义的排错时间。
6. 从 stress 进阶到 stress-ng:用更精细的负载模型做专项压测
6.1 安装 stress-ng 并尝鲜
stress-ng 是 stress 的进化版,提供了超过 200 种 stressor,可以按 CPU 指令类型、内存分配方式、磁盘 IO 模式分别定制。安装方式和 stress 一样,Debian 系apt install stress-ng,RHEL 系yum install stress-ng。一个很有用的参数是--cpu-method,可以指定负载方式,比如sqrt、matrixprod、crc16,替换 stress 那个单一的计算循环。
6.2 用 --seq 和 --class 批量验证系统短板
如果想短时间内把系统主要子系统都过一遍,stress-ng 的--class和--seq能帮上忙。stress-ng --class cpu --seq 1 -t 60会遍历所有 cpu 类 stressor,每个跑 60 秒。更实用的做法是先验证内存,再单独跑磁盘类:
stress-ng --class memory --seq 1 -t 60 --log-file memory-test.log这条命令把 memory 类的所有 stressor 按顺序各跑 60 秒,并在日志文件里记录每次结果。用它做长期老化测试时,我会配合--times输出系统时间统计,加上--min让每个 stressor 至少运行指定时长,避免部分 stressor 因为启动快、退出快而漏测。
6.3 我的压测习惯和一句实话
最后说一点个人习惯。我每次拿到新机器或新内核,都会先跑 10 分钟 stress 冒烟,确认基本负载和散热正常,然后跑 24 小时长测,期间把 dmesg、journalctl、温度曲线全部存起来。曾经有一台机器频繁重启,用 stress 一压就花屏复现,最后查出来是内存插槽虚接导致的不稳定,这种问题如果不靠压测工具逼一下,可能要在业务上挂很久才能暴露,处理起来更被动。压测的价值不在于跑得多狠,而在于把结论沉淀成可对比的数据。希望你压测顺利,一次通过,也希望这些踩坑经验能帮到你。
本文还有配套的精品资源,点击获取