ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux加压测试实战:stress/stress-ng压测CPU、内存与磁盘IO并读结果调优

Linux加压测试实战:stress/stress-ng压测CPU、内存与磁盘IO并读结果调优 简介stress是Linux环境下常用的系统压力测试工具资源内含其1.0.1版本的完整源码包适合系统管理员、运维人员或性能调优开发者使用用于通过模拟CPU计算与内存读写负载检验系统在高负载下的稳定性与极限表现。资源包仅199KB共32个文件以C源码、configure等构建脚本及Makefile.in/am等自动编译配置为主同时包含README、texi/info/html多种格式文档便于查阅使用说明与原理。已有1036人学习下载。通过编译安装该源码可深入理解stress的参数机制如--cpu指定线程数、--vm触发内存压力、--vm-bytes控制分配大小并方便地结合top、vmstat等工具观察系统资源变化还能从configure.in、Makefile.am中了解GNU自动构建流程目录结构简洁适合作为学习系统压力测试与开源工具源码分析的入门素材。无论是快速验证系统稳定性还是深入剖析工具实现都具有实用价值。1. 加压测试工具 stress 到底是什么一条命令让系统现原形做 Linux 系统管理或者运维的人迟早会面对这样的场景新服务器上架、内核大版本升级、散热改造、超频或者虚拟化平台迁移之后没人敢直接拿生产流量去赌稳定性。这时候需要的是一种能快速把系统资源顶到边界的工具。stress 就是 Linux 加压测试里最常用的那个名字它通过 fork 出一批子进程把 CPU、内存、磁盘 IO 这些资源往满里顶配合 top、vmstat、dmesg 去观察负载下的稳定性表现。它测的不是跑分而是系统在边界状态下会不会挂、会不会卡死、会不会在日志里留下 soft lockup 或者 OOM 记录。适合三类人要验收新机器的运维、要验证驱动和内核补丁的研发、以及想真正搞懂 load average 和 CPU 水位背后逻辑的 Linux 学习者。2. 装对工具再动手stress 和 stress-ng 的选型、安装与最小压测命令2.1 先分清 stress 和 stress-ng一个收敛一个重载先把我自己的结论放在前面如果你只是想确认一台机器在满载下会不会过热关机stress 就够了如果你想做内核补丁验证、硬件故障排查或者无人值守的回归测试直接用 stress-ng。stress 是最早那批制造负载的工具设计上很克制。它只做几件事CPU worker 算浮点、vm worker 分配内存并触碰脏页、hdd worker 写临时文件、io worker 制造系统调用、fork worker 制造进程。每一个 worker 就是一个 fork 出来的子进程行为简单到可以用 strace 完整看清楚。这也意味着它没有内置的指标统计、没有错误计数、没有几十种压测方法结果只能靠外部监控工具来读。stress-ng 是 stress 的现代重载版本。它把压测方法从 CPU 一种扩展到了上百种matrixprod、fft、crc、bsearch 这些不同算法目的是覆盖不同的执行路径和指令组合。它还增加了亲和性控制、资源限制、日志、bogo ops 统计、错误计数器甚至能模拟一些故障注入场景。做脚本自动化的时候stress-ng 的--metrics-brief和--log-file会比经典 stress 舒服得多。我一般会在基准验证时两套都装上先用 stress 跑一个五分钟的基础压力确认 top 里 us 水位能到期望值再用 stress-ng 跑一个带方法矩阵的回归确认不同 CPU 指令组合下系统不报错。这不是重复劳动因为我踩到过太多次“stress 满转但系统毫无波澜”的怪事原因往往是虚拟机调度或 cgroup 限额光看 stress 输出根本看不出来。2.2 各发行版安装与五秒跑起来的命令安装命令如下Debian 系和 RHEL 系分开写# Debian / Ubuntu 系 sudo apt update sudo apt install -y stress stress-ng # 验证安装 stress --version stress-ng --version# RHEL / CentOS 系stress-ng 在 EPEL 仓库 sudo yum install -y epel-release sudo yum install -y stress stress-ng装完之后先用一条最小命令把 CPU 压 30 秒验证工具本身能工作stress --cpu 4 --timeout 30运行期间另开一个终端输入top你会看到 4 个 stress 进程各占一个核的 user 态load average 缓缓升到 4.0 附近。30 秒后命令自己退出进程全部消失系统回到空闲。这一步的意义在于先确认工具没装错、权限没问题、终端操作没被容器或虚拟机底层限制。参数说明--cpu 4表示启动 4 个 CPU 压力子进程不是指定 4 核而是这 4 个进程会被调度器分配到 4 个核上跑--timeout 30的单位是秒stress 支持s/m/h/d/y后缀我习惯写成--timeout 30s这种显式写法避免误读。这里有个经常被忽略的点stress 命令的简写参数不少但为了脚本可读建议写全--cpu、--vm、--hdd、--io别贪图短命令。短命令在交互终端用一次没问题写进自动化脚本会让后人看得很费劲。提示第一次压测请开两个终端一个跑压力一个观察避免在循环里反复切换命令。2.3 最小命令的参数清单--cpu、--vm、--hdd、--io 分别压什么先把四类常见的压力参数列成一张对照表后面每章都会反复用到参数默认行为实际压的是什么典型用法--cpu NN 个进程跑浮点 sqrt 循环CPU 算术单元与抢占调度stress --cpu 4 --timeout 60--vm N --vm-bytes MN 个进程 mallocmemset内存分配器、脏页回收与 swap 路径stress --vm 2 --vm-bytes 1G --timeout 60--vm-hang C子进程分配后保持 C 秒再释放内存驻留水位、OOM 判定stress --vm 2 --vm-bytes 1G --vm-hang 5--hdd N --hdd-bytes MN 个进程写大文件后 unlink文件系统写路径、页缓存与 fsyncstress --hdd 4 --hdd-bytes 2G --timeout 120--io NN 个进程反复触发短系统调用系统调用层与进程调度不是块设备 IOstress --io 4 --timeout 60注意表里前两行容易踩坑。--vm默认每个进程分配 256MB但如果你写--vm 2 --vm-bytes 1G两个进程合计要 2G 内存不是总共 1G超了就会触发 OOM。--hdd的默认行为是先写满一个 1GB 临时文件fsync 之后立刻 unlink然后再写下一个所以它压的是“同步写 文件系统回收”这条路跟数据库那种随机小 IO 是两码事。io worker 的细节也值得一提。--io 4并不会让磁盘%util上升它产生的是系统调用层面的压力你会看到 vmstat 的cscontext switches和ininterrupts起飞。所以如果想模拟“大量小请求打到系统调用层”的场景--io是免费的素材想压磁盘队列请直接上 fio后面第三章会展开。到这里stress 的最小命令集已经齐了。下一章就把它从冒烟用到真实场景CPU 满载怎么绑核、内存水位怎么调、磁盘和混合负载怎么组合。3. 按真实场景加压CPU 满载、内存水位、磁盘 IO 与混合负载的写法3.1 CPU 加压场景多核满载与单核热点最常见的场景是验证一台服务器在“所有核都拉满”时散热和电源能不能顶住。命令直接写成# 压满本机所有逻辑核跑 5 分钟 stress --cpu $(nproc) --timeout 300这里用$(nproc)把核数自动传进去省得每台机器去数核。如果机器开了超线程nproc返回的是逻辑核数对压测来说没问题因为我们要的就是逻辑 CPU 全部打满。观察是否生效用两分钟内的快照top -b -n 1 | head -20重点看两处%Cpu(s)行里的us四核机器应当接近99.xload average应当在 4 左右。如果us只到 50%先去确认这台机器是不是虚拟机宿主机是否限制了 CPU再看wa列是不是被磁盘拖住了。别急着加 worker 数先把环境弄干净。更细化的场景是单核热点。比如验证中断绑核、DPDK 应用或者某个单线程服务需要只压某个核taskset -c 2 stress --cpu 1 --timeout 60taskset -c 2把 stress 进程绑定到 CPU2其它核保持空闲方便观察绑核是否生效。验证时用 mpstat 或 top 按1展开每核视图看到 CPU2 的 us 接近 100% 而其它核接近 0说明绑核有效。如果想模拟“高峰期 70% 水位”而不是极端满载用 stress-ng 直接给负荷百分比stress-ng --cpu 8 --cpu-load 70 --timeout 300s --metrics-brief注意--cpu-load 70的算法是让子进程忙闲交替来维持平均 70% 水位CPU 使用曲线会有锯齿。这个模式适合做容量试探不适合做稳定性验收——稳定性验证还是得 100% 压满因为问题往往出现在散热拐点和电源峰值而不是平均功耗。load average 是滑动平均值启动后看着它爬个几十秒再下结论不要刚点回车就误判压力没起来。3.2 内存加压场景水位抬升、swap 触发与 OOM 边界内存压力是最容易出事故的地方先讲一个原则压测内存之前必须先看free -h确认 available 水位再决定--vm-bytes敢不敢写。我见过一次同事直接把--vm-bytes 8G写到一台 8G 机器上结果系统瞬间 OOM把同一台机器上的业务进程杀了压力测试直接变成线上事故。安全的基础写法是这样# 先看内存水位 free -h # 两个 worker各分 2G保持驻留 30 秒后释放 stress --vm 2 --vm-bytes 2G --vm-hang 30 --timeout 120注意这条命令的分配逻辑是每个 vm worker 独立 malloc 2G 并 touch 全部页然后进入 sleep 状态保持 30 秒再释放。两个 worker 合计 4G要保证 available 大于 4G 再加上系统自身占用 2G 左右否则直接触发 OOM。如果想要故意测 OOM 边界做验证用 stress-ng 并加--oomable让子进程被 OOM killer 杀掉而不牵连主机上的其它业务# 压测进程允许被 OOM但作为隔离实验 stress-ng --vm 4 --vm-bytes 75% --vm-hang 1 --oomable --timeout 60s75%的写法是占 available 内存的百分比这是 stress-ng 的扩展能力经典 stress 只收字节数。跑的时候开着vmstat 1盯 si/so 两列si 升说明内存开始从 swap 换入so 升说明有页被换出这两列一旦抖动起来说明系统已经在内存瓶颈上挣扎。另一个实用技巧压测后如果需要快速恢复干净内存基线可以清理 page cache 和 swap 残留但前提是压测进程已经完全退出# 确认 stress 子进程都已退出后再执行清理 pgrep -a stress echo 3 /proc/sys/vm/drop_caches swapoff -a swapon -a最后一条swapoff -a swapon -a会让内核把 swap 里的页倒回内存如果内存已经被腾空这个操作很快如果内存仍然紧张反而会卡一阵子。所以一定要等压力进程退出后再做这也是我压测脚本里放进 trap 里的收尾动作。3.3 磁盘与 IO 加压场景同步写密集与 fsync 风暴经典 stress 的--hdd参数大家经常误解为“压磁盘”其实它压的是文件系统的同步写和回收路径不是块设备的随机 IO。它的行为是每个 worker fork 出来反复执行“创建临时文件 → 写满 → fsync → unlink → 再创建”的循环所以你会看到 iostat 里%util波动但文件系统剩余空间不变。一个可以快速复现的写法stress --hdd 4 --hdd-bytes 2G --timeout 120 # 另一个终端 iostat -x 1iostat -x 1重点看%util、await、svctm三列。await持续走高说明 IO 队列在排队%util接近 100% 说明设备饱和。注意 stress 的 hdd worker 会大量触发内核的fsync和unlink所以这个场景适合验证“文件写多删多”的目录型负载而不适合验证数据库那种 4K 随机写。如果是数据库存储或者云盘 IOPS 验收直接上 fio别在 stress 的 hdd 上浪费时间。我常用的随机写模板fio --namerandwrite --ioenginelibaio --iodepth32 --rwrandwrite \ --bs4k --size1G --numjobs4 --direct1 --group_reporting说明--direct1绕过页缓存--iodepth32控制队列深度--bs4k模拟数据库典型的页大小--numjobs4并行 4 个任务。fio 结束后会输出 IOPS 和延迟分位数这才是磁盘性能验收该看的东西。我的习惯是两层配合先用 stress--hdd做十分钟冒烟确认文件系统路径没报错再用 fio 做正式基准二者验证的目标不同。lsiost 和 mpstat 需要 sysstat 包别漏装。3.4 混合负载web 服务、数据库与带外监控的模拟方式真实的服务不会只压 CPU 或只压内存而是几种资源同时拉扯。stress-ng 支持一条命令里组合多类压测器stress-ng --cpu 4 --vm 2 --hdd 2 --io 2 --timeout 600s --metrics-brief这条命令会同时维持 4 个 CPU worker、2 个内存 worker、2 个磁盘 worker 和 2 个 syscall worker。注意--vm 2没写--vm-bytes时默认每个内存 worker 只占 256MB如果想模拟更高的内存水位要显式写--vm-bytes。提示--vm不写--vm-bytes时的默认值很容易被忽略混合负载场景下内存压力会远低于 CPU 压力导致你以为压了内存实际内存水位根本没动。如果手边只有经典 stress可以把多个进程放后台组合nohup stress --cpu 4 --timeout 600 /tmp/stress-cpu.log 21 nohup stress --vm 2 --vm-bytes 1G --timeout 600 /tmp/stress-mem.log 21 nohup stress --hdd 2 --hdd-bytes 1G --timeout 600 /tmp/stress-hdd.log 21 三个后台任务的日志分别写到 /tmp 下压测结束用pgrep -f stress确认退出状态。这种做法的好处是每个 worker 组独立便于单独 kill 某一类压力缺点是进程组管理混乱清理时要小心后面避坑章节会说。如果是模拟 web 服务的负载让压力工具和流量工具配合会更真实先启动 stress 稳定 CPU/内存水位再让 ab/wrk 向本地 nginx 打请求观察 p99 延迟随压力增大的漂移。这条链路我只丢个思路具体数值因环境而异但它是判断“系统在资源水位升高时是否仍能保证尾延迟”的最直接办法。4. 读结果才能调优用 top、vmstat、mpstat、dmesg 判断压力是否压到点子上4.1 top 与 uptime验证 CPU 与 load average 是否按预期走加压测试做完不算完关键是确认压力真的作用到了目标资源上。我用top和uptime做第一步验证。uptime top -b -n 1 | head -20uptime输出最后一行的 load average 有三个数字分别是 1、5、15 分钟的平均运行队列长度。压测阶段四核机器跑stress --cpu 4load average 应当接近 4.0如果只到 1.5 左右基本可以判断是某个环节限制了 CPU 配额比如虚拟机 CPU 上限或 cgroup 的 cpu.max。top -b -n 1抓一帧快照重点看%Cpu(s)行。us列是用户态占用sy列是内核态wa列是 IO 等待。CPU 压力正确时us应该占绝大多数如果sy异常高说明系统调用或锁竞争才是瓶颈。这时候待观察的不再只是 CPU 温度而是内核的锁和调度路径。在逻辑核较多的机器上top默认只显示整体 CPU 行按键盘1可以展开每核视图。多核满载时应该所有核都接近 100%如果只有一两个核满其余空闲说明任务的并发度没起来或者 NUMA 绑定导致 worker 都挤在某一路内存上。此时用 stress-ng 加--taskset参数做核绑定能改善均匀性。4.2 vmstat 与 mpstat内存水位、上下文切换与每核分布top给整体印象vmstat给资源间的因果关系。vmstat 1 5每秒刷新一次采样 5 次。看三组列r是运行队列长度压测时应该大于等于核数b是阻塞进程数长时间大于 0 说明 IO 或锁把人卡住了si/so是 swap 换入换出持续非零说明内存已过载cs是上下文切换--io压力下会异常飙升这能解释为什么 sys 占比高。举个例子stress --cpu 4跑的时候我们期望r接近核数、cs平稳如果r只有 1 但cs极高说明进程在频繁睡眠唤醒而不是真忙大概率是 CPU 亲和性配置或 hypervisor 调度造成的。这个结论在容器里尤其常见下一章避坑部分会详细展开。每核的分布要看mpstat它比 top 展开核视图更精确mpstat -P ALL 1每行对应一个 CPU%usr高说明在跑应用代码%sys高说明在内核路径里。如果各核的%usr差异超过 20 个百分点就要检查是不是有中断绑核、NUMA 内存分配不均、或者某些核被别的虚机抢占。这个差异在物理机上通常很小在云主机上则可能很明显。如果%steal列持续出现非零值说明你的虚机 CPU 时间被宿主机抢走了。这时压测数据不能直接作为硬件稳定性结论只能代表这台虚拟机的调度表现。4.3 dmesg 与系统日志OOM、soft lockup 与硬件错误的第一现场CPU 和内存压力测试最容易在dmesg里留下第一手证据压测结束后的标准动作是先扫一遍内核环形缓冲区dmesg -T | grep -iE oom|soft lockup|watchdog|hardware error|mce|call trace | tail -50-T参数把时间戳转成可读时间。压测过程中出现过 OOM 时这里会看到 oom-killer 的完整决策记录包括杀掉的进程名、内存用量、各进程的 oom_score。如果杀的是 stress 自己的 vm worker说明内存压力设置合理但越过了边界如果杀的是业务进程那就是事故必须回头把--vm-bytes调低并检查监控告警有没有第一时间触发。出现watchdog: BUG: soft lockup时说明某个 CPU 长时间无法响应调度中断通常伴随硬中断处理函数卡死或驱动死循环。这种现象未必是 stress 本身造成的更多是压力叠加后把驱动或固件的问题逼出来了。做法是先用taskset把压力绑到出问题的核上复现再做二分排查。硬件错误这类mce日志一旦出现在压测过程中我通常会直接结束测试因为 CPU 或内存的错误不排除会扩大。建议先用 memtest86 或 stress-ng 的--memthrash单独验证再决定是退硬件还是继续跑。有些机器在极端散热条件下会出现可恢复 MCE但这已经不属于“工具问题”的范畴而是硬件选型和散热设计该管的事。5. Linux 加压测试的避坑指南从孤儿进程到伪压力的五个真实翻车现场5.1 忘了写 --timeout压力进程变成系统“钉子户”现象压测命令只写了stress --cpu 8没有--timeout。下班前启动第二天早上发现 load average 还是 8 点多ssh 登录后 top 里 8 个 stress 进程还在原地打转。原因stress 默认是无限期运行直到收到信号退出。没有 timeout 的压测就是一台服务器的“钉子户”人走了压力还在。解决命令尾部永远带上--timeout并且用双保险外部再加timeout命令包装。timeout 3600 stress --cpu 8 --timeout 3590timeout命令的兜底时间是 3600 秒stress 自己 3590 秒退出外层多留 10 秒是为了处理 stress 子进程退出过程中的收尾。如果已经出现孤儿进程用pkill -9 -f stress清理-9直接终结避免 SIGINT 被某些子进程忽略。5.2 内存加压直接把业务进程 OOM--vm-bytes 的乘法逻辑现象同事在数据库主机上跑stress --vm 2 --vm-bytes 4G机器 available 只有 10G原以为只占 4G 内存结果数据库进程直接被 OOM killer 杀了。原因--vm-bytes是单个 worker 的内存两个 worker 实际要 8G再加上数据库自身缓存占用系统 available 迅速见底。stress 的 vm worker 会 touch 每一页不做预留内存不够时内核就会按 oom_score 挑进程杀。解决压测前先看free -h记住公式总内存占用 worker 数 × vm-bytes 系统固定开销。预留空间至少要 20%。对数据库主机做内存压测前最好先做一次全量备份或直接放到从机上验证。free -h stress --vm 2 --vm-bytes 1G --vm-hang 30 --timeout 1205.3 用 stress 压磁盘其实是伪压力fio 才是该用的工具现象用stress --hdd 4压一台新 SSDiostat 里%util只有 30%延迟也不高测完得出结论“磁盘性能很好”但后续上线数据库跑批磁盘明显成了瓶颈。原因stress 的 hdd worker 是同步写和 unlink 循环队列深度低无法像数据库那样打出高并发随机 IO。它压的是文件系统路径和页缓存回收不是块设备队列深度。解决如果目标是从块设备角度看压力直接用 fio。fio --namerandread --ioenginelibaio --iodepth64 --rwrandread \ --bs4k --size2G --numjobs8 --direct1 --group_reporting用--iodepth64和--numjobs8把队列打深看 IOPS 和延迟分位。stress 的 hdd 只保留在“验证文件系统不会报错”这个冒烟级别真正的磁盘验收交给 fio。5.4 在容器里压测压了个寂寞cgroup 边界误解现象容器里跑stress --cpu 32容器内 top 显示 32 个进程满载但容器 load average 一直不高业务仍抱怨“没感觉到压力”。原因容器 CPU 配额由 cgroup cpu.max 控制。如果配额是 4 核那 32 个 worker 也只能在 4 核里轮转容器内看到的“满载”是配额内的满载。更麻烦的是load average 在容器内读取的是 namespace 视角或宿主机视角容易出现错位。解决压测要看宿主机视角。用systemd-run --scope或直接在宿主机上跑 stress再看宿主机的 mpstat。如果必须容器内压测先确认配额cat /sys/fs/cgroup/cpu.max然后让 worker 数等于配额核数别按容器内 nproc 报上去的数值否则压测结果没有任何参考意义。5.5 CtrlC 之后系统还在喘进程组清理法现象压测跑了一半按 CtrlC 想停终端返回了但 top 里还有十几个 stress 子进程在跑load average 居高不下。原因stress 的父进程收到 SIGINT 退出时它 fork 出的子进程未必在同一进程组里终端的中断信号只发给了前台进程组。某些情况下子进程会变成孤儿继续执行原来的压力循环。解决不要只 kill 父进程直接按进程名清pkill -9 -f stress清完之后用pgrep -a stress确认没有残留。如果是 stress-ng它内部有信号处理SIGINT 能干净地结束所有 worker但为了保险我仍然会在脚本的trap里放pkill -9 -f stress-ng防止异常路径挂住。trap pkill -9 -f stress-ng; pkill -9 -f stress EXIT6. 进阶用 stress-ng 做内核稳定性回归与限时自动回收的实战技巧6.1 用 --metrics-brief 收口回归数据做内核稳定性回归时我习惯把压测写成一个脚本跑完自动输出指标并清理现场stress-ng --cpu 4 --vm 2 --hdd 1 --io 1 \ --timeout 30m --metrics-brief \ --log-file /tmp/stress-ng-regress.log--metrics-brief会在结束时输出每类压测器的运行时间、bogo ops 和错误计数。--log-file把整个过程写到日志方便脚本按时间戳归档。bogo ops 本身是一个相对值不用太纠结绝对值但如果同一台机器两次运行的 bogo ops 下降超过 10%可以怀疑频率降级或散热翻车。6.2 用 --seq 快速遍历 CPU 方法确认指令路径没有隐藏故障我还会跑一轮方法矩阵把所有 CPU 压测方法轮流过一遍时间控制在五分钟以内stress-ng --seq 1 --timeout 5m --metrics-brief--seq 1会让 stress-ng 按顺序自动跑所有压测器每个方法跑 1 秒后自动切换。这轮跑完如果--metrics-brief里 ERR 计数全部为 0再去做长时稳定性回归效率会高很多。遇到 ERR 非零时先定位是哪个方法再把该方法单独跑长时并配合 dmesg 抓日志。收个尾。我自己的习惯是压测脚本永远带三样东西外层 timeout 兜底、内层 --timeout 限时、以及结束后的 pkill 清理。压测结束后还要回到空闲状态再观察至少 10 分钟重点看散热风扇能否回落、温度曲线是否下降这个动作能提前发现散热设计问题。以上这些步骤组合起来才是完整的一次加压测试。希望帮到你。本文还有配套的精品资源点击获取
返回列表