Linux压测工具stress详解:CPU、内存、IO与磁盘加压实战
简介这是一份面向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} 21 # 检查子进程是否暴毙 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} 21 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_memory2不允许超额分配让 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 百分百发热过了一晚直接热关机第二天想复盘都没数据。记住压测要压的是系统的边界不是压你自己的项目工期。希望帮到你。本文还有配套的精品资源点击获取