CentOS 7离线安装stress 1.0.4:源码编译、压测参数与排错验证
简介面向Linux运维、测试与性能调优人员提供CentOS环境下stress离线部署与性能压力测试所需的配套资料重点解决无外网服务器无法直接安装压测工具、依赖不完整的问题。压缩包共43个文件约46.66MB以11个rpm依赖包和stress-1.0.4源码文件为主包含configure、C源码、m4、install-sh等构建脚本以及readme、news、changelog、texi/info等说明文档便于完成编译安装、依赖核对和版本确认。目录中同时保留配置检查、版本检查、安装辅助和示例说明等材料便于在受限网络环境中复用与排错。内容涉及sar命令与Linux性能压测场景可用于CPU、内存、IO等基础压力实验环境搭建帮助读者理解离线安装流程、组件依赖关系及监控数据查看方式。对需要撰写压测记录、核对系统负载或整理部署文档的读者也较友好。已有2598人学习下载适合需要离线部署stress并补齐系统监控、性能验证思路的初中级Linux使用者参考。1. 版本选择CentOS 上离线装 stress 1.0.4 前要先认的三件事前阵子接手一台内网 CentOS 7 机器最小化安装yum 源指向本地仓库。要做上线前的容量摸底顺手敲了yum install stress回了一行No package stress available然后就没有然后了。机器不通外网也不方便临时开通道只能老老实实走离线安装。stress 这个工具本身小得可怜一个 C 文件加几个头文件编出来几百 KB坑全在环境上目标机可能没装 gcc装好的二进制拷到另一台机器可能报 GLIBC 版本对不上sudo之后还可能提示找不到命令。这篇就把我在 linux 压力测试环境里反复装 stress 的过程记下来——版本怎么选、依赖怎么补、怎么编、参数怎么配、翻车之后怎么救以及装完怎么确认它真的在压这颗 CPU。2. 备料清单离线机上的 gcc、make 与编译前置核对离线安装最怕的不是缺某一个包而是装到一半才发现缺回来补又得重新走一遍流程。所以我在动手之前会把目标机的情况一次性摸完把结论记在工单里后面每一步都对着这份信息走。2.1 先把目标机的家底摸清楚同一个 stress 二进制在 x86_64 上能跑拿到 aarch64 上就是一句cannot execute binary file在 CentOS 7 上编好的拷到 glibc 更老的系统上又会报version GLIBC_2.14 not found。所以离线安装的第一原则是在哪台机器上跑就在哪台机器上编实在不行也要保证架构和系统大版本一致。# 一次性把关键信息打出来贴到工单里备查 cat /etc/redhat-release # 系统大版本CentOS 7.x 还是 8.x uname -m # 架构x86_64 还是 aarch64 getconf LONG_BIT # 32 位还是 64 位 nproc # 逻辑核数后面配 --cpu 要用 free -m # 内存总量后面配 --vm-bytes 要用 df -h /usr/local /tmp /data # 安装目录、压测临时目录的剩余空间 ulimit -a # 进程数、文件句柄、栈大小等限制nproc和free -m这两个数后面会直接进压测命令先记下来能省不少事。ulimit -a里重点看open files和max user processesstress 起几十个 worker 时会 fork 大量进程限制太紧会直接fork: Resource temporarily unavailable。df -h则是为--hdd场景铺路磁盘写满在压测里是实打实的生产事故。2.2 gcc、make 与 configure 的核对顺序很多人以为源码编译必须凑齐 autoconf、automake、libtool 这一整套其实 stress 用不上。它发布出来的 tar 包里通常已经带了生成好的configure脚本真正的编译依赖只有 gcc 和 make。# 编译 stress 真正需要的东西比想象中少 gcc --version make --version ld --version # 顺手确认 C 库头文件在不在缺了它 make 会报 stdio.h not found ls /usr/include/stdio.h rpm -q glibc-develld属于 binutils正常装 gcc 时会作为依赖一起装上glibc-devel提供stdio.h、stdlib.h这些头文件编译任何 C 程序都绕不开。最小化安装的 CentOS 往往这三样全无gcc --version直接command not found。判断要不要 autotools解压前就能看出来# 看包里有没有现成的 configure有就不用装 autotools tar -tzf stress-1.0.4.tar.gz | grep -E (^|/)configure$|Makefile\.in$命令输出里出现configure和Makefile.in说明是发布包./configure make直接能走如果只有configure.ac、Makefile.am那才是开发态源码得先autoreconf -i这时候才需要 automake 和 autoconf。我一般优先找前者省一层依赖。2.3 缺依赖时用同版本安装镜像搭本地 yum 源离线机补 gcc最省事的做法是挂载同版本的安装镜像做本地源而不是满世界找 RPM 包手工rpm -ivh。手工装 RPM 最难受的是依赖链gcc依赖cpp、glibc-devel、kernel-headers一环没对上就卡住本地源交给 yum 自己解。# 1) 挂载本机或同版本的安装镜像文件名以实际为准 mkdir -p /mnt/cdrom ls -lh /opt/iso/ mount -o loop /opt/iso/CentOS-7-x86_64-DVD-xxxx.iso /mnt/cdrom # 2) 写一个只指向本地目录的 repo 文件 cat /etc/yum.repos.d/local-iso.repo EOF [local-iso] nameLocal ISO baseurlfile:///mnt/cdrom gpgcheck0 enabled1 EOF # 3) 清缓存重建只装编译要用的包 yum clean all yum makecache yum install -y gcc make glibc-devel几个参数值得展开。baseurlfile:///mnt/cdrom这里的三个斜杠不能少两个斜杠会被当成主机名解析报Cannot retrieve repository metadata。gpgcheck0是内网隔离环境的常见取舍省掉导入 GPG KEY 的步骤如果环境有合规要求把镜像里的RPM-GPG-KEY-CentOS-*导入后改成gpgcheck1更稳妥。yum clean all必须在改完 repo 后跑一次否则旧的元数据缓存会让新源看起来“不存在这个包”。装完立刻回头验证别等到编译时才发现# 装完确认三件套齐了版本号也一起记下来 gcc --version | head -1 make --version | head -1 rpm -q glibc-devel如果环境里已经有别的内网 yum 源装的时候建议显式限定仓库避免版本串台yum install -y --disablerepo* --enablerepolocal-iso gcc make glibc-devel。这一步我踩过一次坑——内网源里的 gcc 版本比本机 glibc 新装完能编译但链接报错排查了半天。3. 编译落地stress 源码包从上传到 make install 的完整走法依赖备齐之后编译本身并不复杂真正决定成败的是几个细节包有没有校验、configure的日志有没有留、装完的路径有没有进 PATH。这三件事每一件都能单独写一条踩坑记录。3.1 上传、校验与解压的目录约定源码包我一律放/usr/local/src二进制装到/usr/local/bin好处是卸载的时候删两个目录就干净了不用去系统目录里翻。# 统一放到 /usr/local/src卸载的时候好找 mkdir -p /usr/local/src cd /usr/local/src # 上传方式按环境选scp、rz、或者从共享目录 cp # scp stress-1.0.4.tar.gz usertarget-host:/usr/local/src/ # 拿到包先看大小和校验值别急着解压 ls -lh stress-1.0.4.tar.gz sha256sum stress-1.0.4.tar.gz校验这一步在离线环境里格外重要。文件经过 U 盘、跳板机、共享目录几次中转损坏的概率不低而 tar 包损坏的表现往往是解压到一半报unexpected EOF看起来像磁盘问题实际是包坏了。校验值跟源端对一遍能省掉后面一大堆误判。# 先看包内结构确认顶层目录名 tar -tzf stress-1.0.4.tar.gz | head -20 # 解压并进入源码目录 tar -xzf stress-1.0.4.tar.gz -C /usr/local/src cd /usr/local/src/stress-1.0.4 # 确认 configure 是现成的还是需要重新生成 ls -l configure configure.ac 2/dev/nullhead -20那一步是为了确认顶层目录名。有些包解压出来是stress-1.0.4/有些直接铺平到当前目录盲写cd很容易进错地方。configure存在就直接用只有configure.ac就先跑autoreconf -i这一步会用到 automake前面没装的话这里就卡住了。3.2 configure 的参数与 make 的失败信号configure的参数不多最常用的是--prefix它决定make install之后二进制落在哪。# 标准装法装到 /usr/local/bin ./configure --prefix/usr/local # 保守装法留一份完整日志出问题直接翻 ./configure --prefix/usr/local /tmp/stress-configure.log 21 tail -30 /tmp/stress-configure.log--prefix/usr/local是默认值写出来是为了明确不想污染系统目录的话可以改成--prefix/opt/stress之后靠软链接暴露命令# 装到独立目录再用软链接挂到 PATH 里已有的位置 ./configure --prefix/opt/stress # 后面 make install 之后执行 ln -sf /opt/stress/bin/stress /usr/local/bin/stressconfigure失败时不要只看终端最后一行真正的信息在/tmp/stress-configure.log或者源码目录下的config.log里那是排错时最该先翻的记录。常见的失败信号对照如下configure / make 输出含义处理方向no acceptable C compiler found in $PATH没装 gcc或 gcc 不在 PATH回 2.3 用本地源装 gccC compiler cannot create executablesgcc 在但链接器或 C 库头文件缺装 binutils、glibc-devel翻 config.logmake: gcc: Command not foundconfigure 阶段用了别的编译器变量./configure CC/usr/bin/gcc重跑fatal error: stdio.h: No such fileglibc-devel 缺失yum install -y glibc-develPermission denied写 /usr/local当前用户不是 root或目录属主不对用 root 执行或换--prefix到家目录configure通过之后进make# 编译量很小-j4 足够并发数别超过 nproc make -j4 21 | tee /tmp/stress-make.log # 关键看有没有真正的 errorwarning 可以放过 grep -iE error /tmp/stress-make.logstress 源码比较老编译时出现几条 warning 属于正常现象比如隐式函数声明、未使用变量不影响功能真正要盯的是error和Error 1。tee的作用是把输出同时留一份到文件方便事后比对——有些环境下终端滚动缓冲区有限报错一闪就没了这是血泪经验。3.3 make install 与 PATH 上的两个隐蔽坑# 安装把二进制放到 --prefix 指定的 bin 目录 make install # 装完立刻确认落在哪、能不能跑 ls -l /usr/local/bin/stress /usr/local/bin/stress --version which stress能直接用绝对路径跑通说明二进制本身没问题which stress找不到那就是 PATH 的问题。处理方式有两种我倾向写profile.d比改/etc/profile好维护# 写进 profile.d所有登录 shell 都能拿到 cat /etc/profile.d/local-bin.sh EOF export PATH/usr/local/bin:$PATH EOF chmod x /etc/profile.d/local-bin.sh # 当前会话立即生效 source /etc/profile.d/local-bin.sh第二个坑更隐蔽普通用户stress --version正常sudo stress --version却提示command not found。原因是 sudo 读的是/etc/sudoers里的secure_path跟当前 shell 的$PATH完全是两回事。# 看看 sudo 用的是哪条 PATH sudo grep secure_path /etc/sudoers # 典型输出Defaults secure_path /sbin:/bin:/usr/sbin:/usr/bin改法是用visudo编辑把/usr/local/bin拼进secure_path不想动 sudoers 的话脚本里一律写绝对路径/usr/local/bin/stress也行。同样的问题在 cron 里会重演一遍cron 的默认 PATH 更短定时压测任务里写相对命令几乎是必然翻车。4. 参数配置stress 的 CPU、内存、IO 三类压测场景怎么调装完只是拿到了工具真正决定压测有没有意义的是参数。stress 的参数不多但每个都有明确的语义边界配错方向得到的数据还不如不测。4.1 CPU 压测--cpu 的数量与 --timeout 的搭配# 所有逻辑核跑满持续 60 秒打印 worker 进度 stress --cpu $(nproc) --timeout 60 --verbose # 只压一半核观察部分负载下的调度和温升 stress --cpu $(( $(nproc) / 2 )) --timeout 120 # 带 backoff让 worker 错峰启动避免瞬间抢满 CPU stress --cpu 4 --backoff 100000 --timeout 60--cpu N的语义是 fork 出 N 个 worker每个都在做sqrt()浮点运算的死循环属于纯用户态计算压力不产生 IO。N 超过nproc并不能压出更高负载多出来的 worker 只会在运行队列里排队测到的是上下文切换开销而不是 CPU 算力所以--cpu一般取nproc或略少。--timeout N是软定时到点后 stress 给 worker 发信号worker 打完当前这一轮循环再退出所以实际耗时可能比 N 略多几秒。这个参数在压测里是必须留的兜底——我见过有人不加--timeout直接stress --cpu 8然后开另一个终端干别的去了回来发现机器已经满载跑了两个小时。--verbose打开后启动时会打印一行dispatching hogs: 8 cpu, 0 io, 0 vm, 0 hdd结束时打印successful run completed in 60s。这行汇总信息很值钱worker 数跟参数对不对得上一眼就能看出来。4.2 内存压测--vm-bytes 的取值边界内存场景是三类里最容易把机器压到失联的因为一旦触发 OOM killer被挑中的进程不一定是 stress。# 2 个 worker每个 malloc 512M持续 60 秒 stress --vm 2 --vm-bytes 512M --timeout 60 --verbose # 只分配不释放观察常驻内存持续上涨 stress --vm 1 --vm-bytes 1G --vm-keep --timeout 60 # 分配后挂起模拟占着内存不干活的场景 stress --vm 1 --vm-bytes 1G --vm-hang 30 --timeout 90--vm N是 worker 数--vm-bytes B是每个 worker 申请的内存总量是两者的乘积默认每个 worker 256M。--vm-keep表示申请后不释放、循环复用同一块内存用来观察 RSS 的真实增长不加则是反复 malloc/free产生的是分配器压力。--vm-hang N是申请完睡 N 秒再释放用来模拟内存被长期占住的形态。取值上我一般留 15% 到 20% 的余量给内核和 sshd# 取物理内存的 70%两个 worker 平分 total$(free -m | awk /^Mem:/{print $2}) per$(( total * 70 / 100 / 2 )) stress --vm 2 --vm-bytes ${per}M --timeout 60 --verbosefree -m输出的第二行以Mem:开头$2是 total 列单位 MBawk匹配行首是为了避开Swap:那一行。算出来的per是两个 worker 各自的份额加起来占七成。剩下的三成不是浪费是留给系统响应你敲命令的空间。4.3 IO 与磁盘--io 和 --hdd 别在根分区上跑# io worker 反复调用 sync()制造回写压力不落大文件 stress --io 4 --timeout 60 --verbose # hdd worker 在当前目录反复写、删临时文件必须有足够空间 mkdir -p /data/stress-tmp cd /data/stress-tmp df -h . stress --hdd 2 --hdd-bytes 1G --timeout 60 --verbose--io N的 worker 做的是sync()循环把页缓存刷到磁盘压力落在回写路径上不产生大文件适合观察iostat里的wkB/s和await。--hdd N才是真正写文件每个 worker 默认 1G写到当前工作目录所以必须先cd到专门目录、先df -h .确认空间。在/根分区或者有业务数据的目录里跑--hdd属于自己给自己制造故障。跑完检查一下临时文件有没有残留# 正常退出会 unlink 临时文件被 kill -9 则可能留下 ls -lh /data/stress-tmp/把三类场景编排成一个脚本日常用起来更省事#!/usr/bin/env bash # run_stress.sh —— 按场景跑一轮压测日志落到 /var/log/stress set -u LOG_DIR/var/log/stress mkdir -p $LOG_DIR STAMP$(date %Y%m%d-%H%M%S) case ${1:-cpu} in cpu) stress --cpu $(nproc) --timeout ${2:-60} --verbose ;; mem) stress --vm 2 --vm-bytes ${2:-512M} --timeout ${3:-60} --verbose ;; io) cd /data/stress-tmp || exit 1 stress --hdd 2 --hdd-bytes ${2:-1G} --timeout ${3:-60} --verbose ;; *) echo usage: $0 {cpu|mem|io} [size] [seconds] exit 2 ;; esac 21 | tee $LOG_DIR/stress-$STAMP.log echo exit code: ${PIPESTATUS[0]}set -u保证引用未定义变量时立即报错避免空参数把命令拼成stress --cpu${1:-cpu}是默认值写法不带参数时默认跑 CPU 场景tee让输出同时进终端和日志文件PIPESTATUS[0]取的是管道里第一个命令的退出码也就是 stress 的真实结果不加这个拿到的永远是tee的退出码。脚本里用的都是stress相对命令所以要么 PATH 已经配好要么改成绝对路径前面 sudo 和 cron 的坑在这里同样成立。5. 排错避坑离线装 stress 时最常撞上的五个现场离线环境的好处是变量少坏处是出问题时没有搜索引擎帮你兜底。下面这几条是我在不同机器上真实撞过的按现场顺序记下来。5.1 安装阶段的两个硬拦路现象一yum install stress回一句No package stress available。原因CentOS 的基础仓库里本来就没有 stress最小化安装的离线环境更没有额外的软件源所以查不到这个包名。解决转源码编译也就是前面 2、3 章的流程如果环境里恰好有额外源且允许用yum provides */stress能先确认哪个仓库提供它但离线机上这条路基本走不通。别在这条命令上反复试浪费时间。现象二./configure报no acceptable C compiler found in $PATH。原因最小化安装没有 gcc或者 gcc 装了但当前用户 PATH 里没有/usr/bin。前者居多。解决回 2.3 用同版本镜像搭本地源装gcc make glibc-devel装完which gcc确认一次再重跑configure。有个细节值得注意——装完 gcc 之后如果还报同样的错多半是之前configure的缓存没清删掉源码目录里的config.cache和config.log再跑一遍。5.2 运行阶段的三个失控现场现象三普通用户能跑sudo stress提示command not found。原因sudo 走的是/etc/sudoers里secure_path定义的路径不含/usr/local/bin。解决visudo把/usr/local/bin加到secure_path里或者脚本里统一写绝对路径。同一个坑在 cron 任务里会再出现一次而且因为 cron 不打印错误往往只表现为“任务没跑”排查时容易想歪方向。现象四--vm-bytes给太大SSH 直接断开机器 ping 得通但连不上。原因内存申请总量逼近物理内存触发 OOM killer被挑中的进程可能是 sshd 而不是 stress。解决按 70% 上限取值务必带--timeout兜底如果是重要机器压测前确认有控制台或带外管理通道能进。这类事故没有后悔药一旦 sshd 被干掉只能靠控制台救。现象五--hdd跑完发现根分区满了系统开始报各种写失败。原因--hdd写的是当前工作目录默认每个 worker 1G两个 worker 就是 2G在/下跑等于拿系统盘做靶子。解决先cd到专门的压测目录df -h .确认剩余空间至少是worker 数 × hdd-bytes的两倍跑完ls确认临时文件已被清理。被kill -9中断时 stress 来不及 unlink需要手工清理残留的大文件。5.3 一条能收敛问题的排查顺序撞上问题先别猜按这个顺序看看日志configure阶段看config.logmake阶段看make的完整输出运行阶段看/var/log/messages里有没有 OOM 记录。看进程ps -ef | grep stress对一下 worker 数量跟参数是否一致数量不对说明参数解析就有问题。看资源top、vmstat 1、iostat -x 1三条命令能覆盖 CPU、内存、IO 三类现场先确认压的是不是你想压的那个维度。6. 验证跑通三条命令确认 stress 真的在压这颗 CPU装完能跑出--version不算完那只能证明二进制能加载。真正要确认的是参数解释对了、压力确实落在了目标资源上、到点能干净退出。我的验证固定分三步走。第一步先用小参数试跑确认 worker 数和参数对得上# 用 2 个 CPU worker 试 10 秒看 dispatching 那行 stress --cpu 2 --timeout 10 --verbose正常输出里会有一行dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd结尾一行successful run completed in 10s。如果dispatching那行的数字跟你给的参数不一致说明参数拼错了或者被 shell 展开成了别的值。第二步另开一个终端观察实际负载。这一步才是关键输出好看不代表真在压# 分核看 CPU每个核的 %us 应该同步抬高 top -1 # 或者用 sysstat 里的分核视图 mpstat -P ALL 1 5 # 看运行队列和上下文切换 vmstat 1 5对三类场景分别盯不同指标参照下表压测场景观察命令正常表现异常信号CPUmpstat -P ALL 1每个核%usr接近 100%idle接近 0只有单核满说明--cpu参数被 shell 吃掉了内存free -m、vmstat 1used明显上涨si/so变化不大si/so大幅波动说明已经在换页压过头了磁盘iostat -x 1%util上升await变大wkB/s有量%util不动说明目录选错或磁盘是内存盘全部ps -ef | grep stressworker 数等于各参数之和进程数对不上参数没生效第三步确认退出行为干净# --timeout 到点后应该返回 0没有残留进程和临时文件 stress --cpu 2 --timeout 5 echo $? ps -ef | grep stress | grep -v grepecho $?输出 0 表示正常结束如果输出 1 或者 124 之类通常是某个 worker 起的资源没申请到比如--hdd空间不足、--vm内存被 cgroup 限制卡住。最后那条ps应该只剩你自己有残留进程说明有 worker 卡在系统调用里没退出来。从那以后我每次在离线机器上装完任何自编译工具都会强制走一遍这个三步验证——小参数试跑、另一终端看指标、检查退出码和残留。看起来啰嗦但它能在正式压测之前把参数理解偏差、PATH 问题和资源限制全部暴露出来比压到一半机器失联再回头查要省事得多。希望帮到你。本文还有配套的精品资源点击获取