简介:面向 Linux 运维、测试与性能验证人员,提供 CentOS 环境下 stress 压力测试工具的离线安装包,适合无外网或受限网络服务器快速部署,并开展 CPU、内存、I/O 等基础压测。压缩包共 43 个文件,约 46.66MB,包含 stress-1.0.4 源码及 configure、C 源文件、README/HTML 文档,同时附带 11 个 rpm 依赖包(含 gcc-g++-4.8.5 等),兼顾源码编译与离线补依赖。资源还提及 sar 命令,便于压测前后观察系统负载、CPU 与 I/O 指标,形成从施压到监控的基本闭环。已有 2598 人学习下载,可作为 CentOS 压测环境搭建与 stress 工具入门的参考资料。
1. 内网那台 CentOS 上,yum install stress是敲不通的
机房最里侧那排机器是不通外网的。第一次在上面做 linux 压力测试,我很自然地敲了yum install stress,回车之后 yum 转了两秒,甩出一行Cannot find a valid baseurl for repo: base。这套环境其实极其常见:交付前要做稳定性验证的内网 CentOS 7、隔离区里那批只靠堡垒机搬文件的生产机、还有验收方要求现场演示负载的老系统。装不好会怎样?从别的机器随手拷个 rpm 过去,rpm -ivh报一屏 GLIBC 依赖;退而求其次自己编译,装完了发现命令不在 PATH 里;再不然参数写错,--vm-bytes直接超过物理内存,SSH 掉线,人还得找人重启。这套流程适合手上只有内网 CentOS、又必须把 CPU、内存、磁盘三类负载都压一遍的运维和开发。
2. 环境先定死:CentOS 7/8/9 与 stress 1.0.4 的对应关系
离线安装最怕的不是没网,是版本对不上。同样是 CentOS,7 和 8 的 glibc 差了两个大版本,一个在 7 上编好的二进制扔到 6 上就是跑不起来。所以在动手收包之前,先花两分钟把这台机器的底细摸清楚,后面选路线、收依赖、判断兼容性全靠这几个数。
2.1 三条命令摸清底细:发行版、glibc、编译工具链
不要凭cat /etc/issue那行欢迎语判断版本,那玩意儿是可以随便改的。用 rpm 体系自己的命令看,结果才作数。
# 1. 发行版与内核,决定用 yum 还是 dnf,以及包的 el 版本号 cat /etc/redhat-release uname -r # 2. glibc 版本,决定一个二进制能不能跨机运行 getconf GNU_LIBC_VERSION ldd --version | head -1 # 3. 编译工具链是否齐备,决定能不能走源码路线 rpm -q gcc make glibc-devel kernel-headers第一条cat /etc/redhat-release会输出类似CentOS Linux release 7.9.2009 (Core),这里的 7 就是后面所有 rpm 包的 el7 后缀来源,包名、仓库路径、依赖树全部跟着它走。第二条uname -r看内核,压测磁盘和内存的时候,有些内核参数(比如 overcommit)会影响结果,顺手记下来。第三条getconf GNU_LIBC_VERSION是最关键的一行,CentOS 7 是 glibc 2.17,CentOS 8 是 2.28,Stream 9 是 2.34。任何在 glibc 2.28 编译机上打出来的二进制,拿到 2.17 的机器上运行时就会报GLIBC_2.28 not found,这个问题在离线场景里几乎无解,只能重编。
最后那条rpm -q是批量查询,四个包名一起写,缺哪个会明确打印package xxx is not installed。这一步的作用是提前分流:工具链齐全就走源码路线,缺一大片就老老实实走 rpm 路线,别等到./configure跑到一半才发现没 gcc。
常见的版本对照关系如下,收包之前先对号入座。
| 系统 | glibc | 包管理器 | stress 来源 | 备注 |
|---|---|---|---|---|
| CentOS 7.9 | 2.17 | yum | EPEL7 | 最省事的是 rpm 路线 |
| CentOS 8.5 | 2.28 | dnf | EPEL8 | 用dnf download --alldeps |
| CentOS Stream 9 | 2.34 | dnf | EPEL9 | 包名与 8 一致 |
| CentOS 6.x | 2.12 | yum | EPEL6 | 太老,建议源码本地编译 |
提示:CentOS 7 已经在 2024 年停止维护,官方源地址失效是常态。离线机器本来就不联网,但用来收包的那台联网机如果也是 7,记得把仓库指向内网镜像或 vault 归档地址,否则
yumdownloader一样会报 baseurl 错误。
2.2 两条路线怎么选:EPEL 的 rpm 还是本地源码编译
先说一个很多人踩过的认知坑:stress并不在 CentOS 的 base 仓库里,它在 EPEL。所以哪怕机器有外网,只做最小化安装的 CentOS 敲yum install stress也会返回No package stress available。这不是网络问题,是仓库没开。搞清楚这一点,离线方案才有意义——要么把 EPEL 里的那个包连同依赖一起搬进来,要么干脆自己编一个。
stress1.0.4 本身是个很小的 C 程序,官方发布的源码包就是一个 tar.gz,展开后核心代码量很小,编译出来只有一个可执行文件,动态链接只依赖 libc。这带来一个很好的性质:rpm 路线下真正需要搬运的包非常少,通常就是stress一个包,加上可能缺的 glibc 相关(正常系统都有)。而源码路线要搬运的是整条工具链,gcc 加上它的依赖,压缩包体积会大出几十倍。
两条路线的取舍,我一般按这个表来判断:
| 维度 | EPEL rpm 路线 | 源码编译路线 |
|---|---|---|
| 需要搬运的包 | 通常 1~3 个 | 10 个以上,gcc 依赖链长 |
| 总体积 | 百 KB 级 | 几十 MB |
| 对目标机要求 | glibc 版本必须匹配 | 目标机需先装好工具链 |
| 卸载方式 | rpm -e stress | 删掉安装目录即可 |
| 版本控制 | 受限于仓库里的版本 | 想装哪个版本装哪个 |
| 适合场景 | 目标机版本统一、批量部署 | 目标机版本杂乱、只有一台 |
还有第三条路,就是用stress-ng代替stress。功能确实强得多,能压网络、能压调度器、能指定 IO 引擎,但它的依赖是libaio、libattr、libbsd、libmd、libsctp、zlib一大串,离线收包的时候光是理依赖树就能耗掉半天。如果目标只是验证机器在高负载下会不会挂、CPU 频率会不会掉、内存有没有问题,stress1.0.4 完全够用,别给自己找麻烦。
3. 离线包怎么备齐:在一台同版本的有网机器上收依赖
离线安装的核心原则只有一条:离线机上要装什么,就在一台同发行版、同大版本、同架构的联网机上按同样的方式下什么。用 CentOS 8 的机器给 CentOS 7 收包,收得再全也是白搭。这一步做扎实了,后面安装基本不会有意外。
3.1 RPM 路线:yumdownloader 与 repotrack 把依赖树拉全
CentOS 7 用 yum 体系,工具在yum-utils包里。注意yumdownloader只下载不安装,这是它比yum install --downloadonly更顺手的地方。
# 在联网的同版本机器上执行(以 CentOS 7 为例) yum install -y yum-utils epel-release # --resolve 递归解析并下载全部依赖,--destdir 指定落地目录 mkdir -p /opt/offline/stress yumdownloader --resolve --destdir=/opt/offline/stress stress ls -lh /opt/offline/stressepel-release这个包的作用是往/etc/yum.repos.d/里写一份epel.repo,装完才有 EPEL 仓库可用。--resolve是关键参数,它会顺着依赖关系往下找,把所有需要的包一起拉下来,不加这个参数只会得到孤零零一个 stress 包,拿到离线机上照样报依赖错。--destdir后面跟绝对路径,目录不存在时会创建。
如果联网机连 EPEL 也访问不了,可以手写一份 repo 文件指向内网镜像,这一步在隔离环境里很常见:
# /etc/yum.repos.d/epel-local.repo [epel-local] name=EPEL Local Mirror baseurl=http://内网镜像地址/epel/7/x86_64/ enabled=1 gpgcheck=0baseurl要精确到7/x86_64这一层,少一层就是 404。gpgcheck=0只建议在内网可信镜像上用,公网环境还是把 GPG key 一起导进去比较稳妥。
再补一个更保险的工具repotrack,同样来自yum-utils。它和yumdownloader --resolve的区别在于会把整棵依赖树完整展开,遇到版本冲突时能看到全貌,代价是下载量大一些:
# -a 指定架构,-p 指定输出目录 repotrack -a x86_64 -p /opt/offline/stress-full stressCentOS 8 及以上换成了 dnf 体系,命令要跟着换,参数名也不一样:
# --alldeps 等价于 yumdownloader 的 --resolve dnf download --resolve --alldeps --destdir=/opt/offline/stress stress3.2 源码路线的最小离线清单
走源码路线,要搬的不是 stress 本身,而是编译它所需的那套工具链。清单列在下表,缺一个./configure就可能中途停下。
| 包名 | 作用 | 是否必须 |
|---|---|---|
| gcc | 编译器驱动,configure靠它做可用性测试 | 必须 |
| make | 执行 Makefile | 必须 |
| glibc-devel | 提供 crt 对象和链接期库文件 | 必须 |
| glibc-headers | 系统头文件 | gcc 的依赖,自动带入 |
| kernel-headers | 内核头文件 | glibc-devel 的依赖 |
| cpp | 预处理器 | gcc 的依赖 |
| libmpc / mpfr / gmp | gcc 的高精度数学库依赖 | 自动带入 |
| libgomp | OpenMP 运行库 | gcc 的依赖 |
收包的写法有讲究,所有包名要写在同一条命令里:
yumdownloader --resolve --destdir=/opt/offline/toolchain \ gcc make glibc-devel kernel-headers分四次执行看起来更清楚,实际上会漏掉交集部分的依赖,因为每次解析只针对当次的目标集合。一次写全,工具才会把并集算对。另外tar和gzip一般系统自带,不用单独收,但如果目标机做过极端裁剪,先rpm -q tar gzip确认一下。
3.3 打包、搬运与校验
包收齐之后打成一个大包,方便一次性搬进去。文件命名带上发行版和日期,隔几个月回头看还能分清是哪台机器用的。
cd /opt/offline # 打包,命名里带 el 版本和日期 tar -czf stress-offline-el7-$(date +%Y%m%d).tar.gz stress toolchain # 生成校验值,一并带过去 sha256sum stress-offline-el7-*.tar.gz | tee SHA256SUMS校验这一步别省。通过堡垒机、跳板机、U 盘接力搬运的文件,中途截断是真实发生过的,一个几 MB 的包传到一半断了,tar解包时报unexpected EOF,你还以为是包本身有问题。到了离线机上先做这两件事:
# 1. 校验完整性 sha256sum -c SHA256SUMS # 2. 解包到固定位置,后面所有命令都基于这个路径 mkdir -p /opt/soft tar -xzf stress-offline-el7-20250101.tar.gz -C /opt/soft ls /opt/soft/stress-C指定解包目标目录,一定要先mkdir -p,目录不存在时 tar 会直接报错退出。解包后确认ls能看到.rpm文件,说明搬运链路是通的。
4. 安装落地:rpm 一条命令,源码四步
准备工作做完,真正安装其实很快。这里把两条路线的命令和参数都写清楚,包括每一条为什么这么写。
4.1 RPM 路线:一次性装完整组包
最容易犯的错误是rpm -ivh后面跟着一堆包,然后按文件名顺序一个个装。rpm 是逐包处理的,如果排在前面那个包依赖排在后面的包,就会立刻报Failed dependencies并中断。
cd /opt/soft/stress # 方式一:一把装全,rpm 会在本次事务里互相满足依赖 rpm -ivh *.rpm # 方式二:交给 yum 做依赖排序,同时断掉所有远端仓库 yum --disablerepo='*' localinstall ./*.rpm -yrpm -ivh的三个字母分别是 install、verbose、hash,-h会打印进度条,包大的时候能看出卡在哪一段。它的问题是只做很弱的依赖判断,所以包数量多的时候我更倾向第二种。--disablerepo='*'这个参数在离线环境里很重要,它的作用是禁用所有已配置的仓库,避免 yum 在解析依赖时去连那些根本连不上的地址,然后卡在超时上几十秒。localinstall表示从本地文件安装,-y跳过确认。
装完立刻验证文件和元信息:
# 列出这个包装了哪些文件 rpm -ql stress # 查看包信息,确认版本和来源 rpm -qi stressrpm -ql的输出里应该能看到/usr/bin/stress和对应的 man 页。如果只看到 man 页没有二进制,说明装错了包或者装的是个空壳,回去检查一下收包时的仓库配置。
4.2 源码路线:configure 参数的实际意义
源码路线多几步,但每一步都有明确的产出,出问题也好定位。
cd /opt/soft tar -xzf stress-1.0.4.tar.gz cd stress-1.0.4 # --prefix 决定安装根目录,bin 和 man 都挂在这下面 ./configure --prefix=/usr/local/stress-1.0.4 make -j"$(nproc)" make install--prefix这个参数值得单独说。不指定的话默认是/usr/local,二进制直接落进/usr/local/bin,跟其他软件混在一起;指定成带版本号的独立目录,好处是同一个系统上可以并存多个版本,将来不要了直接rm -rf /usr/local/stress-1.0.4就干净了,不留残余。这在需要反复验证不同版本的场景里非常实用。
make -j"$(nproc)"里的$(nproc)会返回当前 CPU 核数,让编译并行跑满所有核。stress 1.0.4 的源码量很小,单核也就几秒钟,这个参数更多是习惯问题,但换成大一点的软件就是几分钟和几十秒的差别。make install会把编译产物按--prefix指定的路径拷过去,注意这一步通常需要 root 权限。
装完之后要让它进 PATH,否则每次都得敲全路径:
ln -sfn /usr/local/stress-1.0.4/bin/stress /usr/local/bin/stressln的三个参数各有用途:-s建软链接,-f在目标已存在时强制覆盖,-n表示如果目标本身是个指向目录的软链接,就把它当普通文件替换掉,而不是往那个目录里面塞。少了-n,重复执行会变成/usr/local/bin/stress/stress这种奇怪结构,很隐蔽。
4.3 装完先做三个确认,再谈压测
不管走哪条路线,装完都先过这三关,三十秒的事,能省掉后面半小时的排查。
# 1. 命令是否能找到 command -v stress # 2. 版本是否符合预期 stress --version # 3. 动态库依赖是否完整 ldd "$(command -v stress)"command -v比which更可靠,它查的是 shell 自己的查找逻辑,包含别名和函数,输出为空说明 PATH 里确实没有。stress --version正常会打印类似stress: version 1.0.4的信息,能打印出来就说明二进制本身没坏。ldd的输出里如果出现not found,说明有运行库缺失,这种情况在源码路线几乎不会遇到(链接的是本机 libc),但在 rpm 跨版本搬运时很典型。
还有一个不花钱的验证方式:直接敲stress不带任何参数,它会打印一份 usage 然后退出。usage 能完整打出来,基本可以判定这个二进制是可用的。
4.4 三条最常用的负载命令模板
参数不复杂,但默认值容易让人误判,先把最容易错的几个说清楚。
CPU 负载最简单的形态:
# -c 指定 CPU worker 数量,-t 指定持续时间,-v 打印过程 stress -c 4 -t 60s -v-c 4表示起 4 个进程做开方运算,制造纯 CPU 负载。数量建议不超过nproc,超了之后超出部分只是在等调度器分配时间片,测到的是上下文切换开销而不是 CPU 算力。-t 60s是超时时间,支持s、m、h后缀,不写这个参数任务会一直跑到你手动 kill。
内存负载要注意--vm-bytes是每个 worker的量:
# 2 个 vm worker,每个分配并反复写 1G stress -m 2 --vm-bytes 1G -t 60s -v-m 2起两个内存 worker,每个 worker 分配--vm-bytes大小的内存并不断写入。也就是说这条命令实际会占用约 2G 内存,不是 1G。--vm-bytes默认是 256M,--hdd-bytes默认是 1G,这两个默认值在做小内存机器测试时经常被忽略。
磁盘负载要先进对目录:
# stress 的 hdd worker 在当前工作目录建临时文件 cd /data/tmp stress -d 2 --hdd-bytes 512M -t 60s -v-d 2起两个磁盘 worker,各自创建、写入、删除文件。这里有个细节:它写在当前工作目录,不是/tmp,所以执行前一定要cd到容量足够、且允许写入的分区。在/分区很小的机器上直接跑,会把根分区写满,然后一堆服务开始报错。
混合负载用来模拟真实场景:
# 同时压满所有 CPU 核、加两个 io worker、一个内存 worker stress -c "$(nproc)" -i 2 -m 1 --vm-bytes 512M -t 120s --backoff 1000000-i 2起两个 io worker,它做的事情是循环调用sync(),把 page cache 刷到磁盘。--backoff 1000000让所有 worker 启动后先等 1 秒再开始干活,单位是微秒,作用是让压测起点对齐,观测工具抓到的曲线更规整。-q是安静模式,不打印过程,适合放到脚本里跑。
5. 离线安装常见问题排查:五个真踩过的坑
离线安装的坑有个共同特点:报错信息都很短,但指向的问题五花八门。下面这五条是按出现频率排的,基本覆盖了大部分场景。
5.1 现象:yum install stress报 No package stress available
现象:机器明明能上网,yum makecache也正常,装别的包都没问题,就是装 stress 提示没有这个包。
原因:stress 不在 CentOS 的 base 或 updates 仓库里,它在 EPEL。最小化安装的系统默认只启用了 base,仓库里自然找不到。
解决:先装epel-release,再yum install stress。如果是离线机器,这个报错往往会伪装成Cannot find a valid baseurl,本质是同一个问题——机器上根本没有可用的仓库配置。这种情况直接走第 3 章的离线收包流程,不要再在目标机上折腾仓库配置。
5.2 现象:rpm 安装时报 Failed dependencies,一屏 GLIBC 相关
现象:rpm -ivh stress-1.0.4-*.el8.x86_64.rpm报libc.so.6(GLIBC_2.28)(64bit) is needed,机器上明明有 glibc。
原因:包是给 el8 编的,目标机是 el7,glibc 版本不够。这个报错不会说"你版本不对",只会说某个符号缺失,很容易被误解成包坏了。
解决:动手之前先用rpm -qpR stress-1.0.4-*.rpm把依赖列出来看一眼,重点看有没有带版本号的libc.so.6(GLIBC_2.xx)。确认版本对不对得上,对不上就回到联网机按目标机的版本重新收包。实在收不到对应版本的包,就走源码路线,在目标机上本地编译,产出的二进制一定和本机 glibc 匹配。
5.3 现象:编译装完提示 stress: command not found
现象:/usr/local/stress-1.0.4/bin/stress明明存在,可执行权限也有,敲stress就是找不到。更有迷惑性的是,普通用户找不到,切到 root 用sudo也找不到。
原因:两个可能。一是/usr/local/bin不在PATH里,二是sudo的secure_path配置里不包含/usr/local/bin,即使登录 shell 的 PATH 有,sudo 之后也会被重置。
解决:先echo $PATH确认,再sudo sh -c 'echo $PATH'对比一下,两个不一致基本就锁定了。最快的办法是建软链接到/usr/bin,那个目录一定在 PATH 和 secure_path 里;另一个办法是hash -r清一下 shell 的命令缓存,有时候是缓存了旧的查找结果。
5.4 现象:一跑内存压测 SSH 就断,dmesg 里有 oom-killer
现象:stress -m 2 --vm-bytes 4G -t 60s刚跑起来,终端就卡住,重连不上,等几分钟才能登进去,dmesg | tail里全是Out of memory: Killed process。
原因:--vm-bytes是每个 worker 的量,2×4G 就是 8G。如果机器只有 8G 内存,再加上系统本身占用,内核的 OOM killer 会挑占用最大的进程杀,sshd 的子进程经常被误伤。
解决:动手前用free -m看 available 那一列,按它的 50%~70% 来定总量,再除以 worker 数得到--vm-bytes。另外 stress 有-n(dry-run)参数,可以先把命令跑一遍看它打算做什么,不实际产生负载。生产机上压内存务必加-t,并且用nohup或 tmux 跑,别让终端断开把进程带走。
5.5 现象:stress -i跑了,iostat 里磁盘 util 一点没动
现象:stress -i 4 -t 60s执行期间,另一窗口iostat -x 1看磁盘%util一直是 0.x,跟没跑一样。
原因:stress 1.0.4 的 io worker 做的事情是循环调用sync(),它把 page cache 刷到磁盘,但数据量取决于缓存里有多少脏页。在内存大、写入少的机器上,这个动作几乎瞬间完成,压根造不出持续 IO 压力。这一点跟直觉差别很大,很多人以为-i就是磁盘压测。
解决:要真实的磁盘写压力就用-d配合--hdd-bytes,它会老老实实创建文件、写入、删除;要测 IOPS 和延迟,直接上fio更合适,stress 在这方面本来就不是强项。搞清楚工具的能力边界,比硬套参数更重要。
6. 装完怎么验证:三组数据确认它真的在干活
安装成功的标志不是"命令能跑",而是"它确实对系统产生了预期的压力"。我的做法是固定跑一遍冒烟,用三组数据交叉确认:命令层、负载层、观测层。
先做命令层的确认,这一步是静态的:
# 版本、路径、依赖三件套 stress --version command -v stress ldd "$(command -v stress)" | grep -i "not found"三条命令的期望输出分别是:版本号行、一个绝对路径、没有任何输出(grep没匹配到东西说明依赖完整)。这一步不过关,后面的压测数据都不可信。
然后是负载层的冒烟,二十秒就够:
# 单核跑 20 秒,看 verbose 输出的实时数据 stress -c 1 -t 20s -v正常输出里会周期性地打印类似dispatching hogs: 1 cpu和最后的successful run completed in 20s,这行 success 是判断进程正常退出的直接证据。跑的过程中另开一个窗口观测:
# 每秒采样一次,共 5 次 mpstat 1 5 # 或者看整体负载和上下文切换 vmstat 1 5mpstat输出里%idle如果能压到接近 0(单核跑满,多核机器上表现为某一个核的 idle 归零),说明 CPU 负载确实生效了。vmstat的r列会持续大于 1,cs上下文切换次数明显上升。这两个数对得上,才能说压测是有效的。
最后是记录。压测的价值在于对比,单次数据说明不了问题,前后不记就更没意义:
# 压测前、中、后各记一次,追加到同一个文件 { echo "== $(date '+%F %T') ==" uptime free -m df -h /data } >> /var/log/stress-baseline.log三次采样分别是:压测前的基线、压测进行中的峰值、压测结束后五分钟的恢复值。三个点连起来看,能回答"机器抗不抗得住"和"压力撤掉之后能不能回稳"这两个问题。尤其是内存压测之后,free -m的 available 应该能回到接近基线,回不去就说明有进程没被正常回收。
一份完整的验证对照表大致是这样:
| 检查项 | 命令 | 通过标准 |
|---|---|---|
| 版本 | stress --version | 输出stress: version 1.0.4 |
| 依赖 | ldd $(command -v stress) | 无not found |
| CPU 负载 | stress -c 1 -t 20s -v | 输出successful run completed |
| 观测对照 | mpstat 1 5 | 至少一个核 idle 接近 0 |
| 内存压测 | free -m前后对比 | 结束后 available 回到基线附近 |
| 磁盘压测 | df -h /data期间查看 | 有增长,结束自动回落 |
从那以后我每次在离线机器上装完 stress,都不会直接交付,一定先跑一遍上面这套:版本、冒烟、观测、记录,四步走完再写进交付文档。吃过一次亏——某台机器上 stress 装是装上了,结果ldd里有个库没找到,一跑就 core dump,现场演示的时候才发现,那场面相当难看。这套固定动作能省掉很多返工。希望帮到你。
本文还有配套的精品资源,点击获取