简介:面向存储性能测试人员与运维工程师的 Vdbench 工具资源包,用于模拟随机读写、顺序读写、混合读写等场景,帮助快速评估硬盘、SSD 及存储阵列的极限 I/O 性能,适合从基础调优到生产环境压力验证的各阶段使用者。压缩包共 61 个文件、约 2.91MB,核心内容涵盖 vdbench 可执行程序与 vdbench.jar/bat 启动脚本、适用于 Linux/Windows/Solaris/HP/AIX 的 so/dll 动态库及 config.sh 配置脚本,并附带 readme.txt、vdbench.pdf 官方说明和 example1~example7 等多组配置模板,以及 seq_read、random_rw 等工作负载示例脚本,便于对照学习和直接修改复用。目前已有 762 人浏览学习。借助包内多平台支持和曲线类测试脚本,读者可快速搭建跨平台性能测试环境,掌握通过配置参数控制 I/O 大小、并发与持续时间的方法,并能根据生成的报告开展吞吐量、延迟和 IOPS 分析,为存储系统选型与故障排查提供实测依据。
1. 为什么存储压测绕不开 vdbench:一份能直接复现的 I/O 性能测试工具
很多人第一次接触 vdbench 是因为 FIO 配到一半实在配不下去了——想测存储阵列的极限带宽,又要随机读写,还得顺带验证数据有没有写坏,FIO 的参数组合能堆满一屏。vdbench 的解法则更直接:一个 Java 壳子加上一堆针对不同系统的 native 库,解压就能跑。它把「存储定义、负载定义、运行定义」拆成三张配置表,想测顺序读就改一行,想加并发就把线程数往上拉,十分钟内能出一份带延迟分布和数据校验的报告。对做存储选型、数据库压测和磁盘故障排查的工程师来说,这份工具的价值在于:它是少数能把「多机分布式压测」和「数据一致性校验」塞进同一个配置文件里的开源方案。这篇笔记基于 vdbench 的完整发行包,从目录结构、跨平台运行、配置写法一路拆到报告解读和踩坑记录,照着复现即可。
2. 解包与跨平台运行:先看懂那堆 .so 和 .dll 再动手
2.1 发行包目录结构:每个文件是干什么的
解压 vdbench.zip 之后,第一眼会觉得乱——一堆 .so、.dll、config.sh、readme.txt 铺在根目录。我最初也踩了「直接双击 vdbench.bat 就跑」的坑,后来才发现这个工具的运行机制是一个 Java 主程序按操作系统去加载对应的 native 库,所有平台相关的二进制文件都被平铺在根目录里。先花两分钟把文件分类认清楚,后面能省一小时排查时间。
| 文件/目录 | 作用 |
|---|---|
| vdbench / vdbench.bat | Linux/Windows 启动脚本 |
| vdbench.jar | Java 主程序,所有逻辑都在这里面 |
| linux64.so / linux32.so | Linux x86_64 和 32 位平台 native 库 |
| solx86-64.so / solx86-32.so | Solaris x86 平台 native 库 |
| sparc64.so | Solaris SPARC 平台 native 库 |
| vdbench64.dll / vdbench32.dll | Windows 平台 native 库 |
| config.sh | Solaris/Linux 下的环境配置脚本 |
| examples/ | 官方示例配置目录,从 example1 到 example7 |
| readme.txt | 版本说明和已知问题列表 |
| swatcharts.txt | Swatch 图形日志说明 |
| build_sds.txt | SDS(软件定义存储)构建说明 |
理解这个结构之后就能明白:如果在 Solaris SPARC 上跑,加载的是sparc64.so,在 64 位 Linux 上跑,加载的是linux64.so。这些 native 库负责实际的系统调用,比如直接 I/O(绕过文件系统缓存)和裸设备访问,Java 层只负责参数解析、调度和数据统计。所以遇到「某个平台跑不起来」的报错,第一反应应该是检查对应的 .so 是否存在、是否有执行权限,而不是去翻 Java 代码。
2.2 Rocky Linux 9 上把 vdbench 跑起来
网上搜「rocky linux 安装 vdbench」,会看到很多帖子绕了一大圈去搞 RPM 包,实际上 vdbench 根本不需要安装,它是纯解压运行的工具,唯一的依赖是 Java。Rocky Linux 9 默认装了 Java 11,但 vdbench 官方推荐 Java 1.8,实测在 Java 11 下大部分功能可以跑,但要小心个别版本在 sd 初始化阶段报类加载错误。常见做法是装 OpenJDK 1.8 并把 JAVA_HOME 指过去,稳妥且不会有兼容性问题。
# 1. 安装 OpenJDK 1.8 sudo yum install -y java-1.8.0-openjdk # 2. 设置 JAVA_HOME 并追加 PATH echo 'export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk' >> ~/.bashrc echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc source ~/.bashrc # 3. 解压 vdbench 并验证 cd /opt unzip vdbench.zip -d vdbench cd vdbench chmod +x vdbench config.sh ./vdbench -e这段脚本做了三件关键事:第一步装的是 1.8 版本而不是系统自带的 11,因为 vdbench 某些老版本在 Java 11 下会在-f解析阶段抛NoSuchMethodError,这是类库兼容性问题,换个 Java 版本就消失;第二步把 JAVA_HOME 写进用户级配置,避免每次开终端都重新 export;第三步的./vdbench -e是自检模式,它会在终端打印当前识别的平台信息,比如Linux x86_64,说明 native 库加载成功。如果-e输出Unable to load native library,那就需要检查linux64.so的权限或完整性。
一个容易被忽略的细节是chmod +x vdbench config.sh。从 Windows 上传 zip 到 Linux 后,文件的执行位会丢失,直接跑./vdbench会报Permission denied。这不是 vdbench 特有的问题,但几乎每个从 Windows 环境转过来的同事都卡过这一步。另外,如果解压后的目录放在 NFS 挂载点上,还要注意挂载选项里有没有noexec,否则就算加了执行权限也跑不了。
3. 配置文件拆解:sd、wd、rd 三层结构与一份真实压测
3.1 三个核心段:存储定义、负载定义、运行定义
vdbench 的配置体系可以理解成「数据从哪读写(sd)、用什么方式读写(wd)、测试怎么跑(rd)」三层。初次接触的人最容易犯的错是把所有参数堆在一个段里,实际上这三个段有严格的上下位关系:rd 引用 wd,wd 引用 sd。sd 定义存储对象,比如某个裸设备分区或某个文件路径;wd 定义 I/O 特征,比如块大小、读写比例、随机/顺序;rd 定义运行参数,比如并发线程数、运行时长、采样间隔。
我一般会用一个最小体系来验证配置正确性:先定义 sd 指向一个测试文件,再定义 wd 限定块大小和读写比例,最后用 rd 控制线程数和时长。下面是一个 4KB 随机读加 70/30 混合读写的最小示例,适合先跑通流程再逐步加参数。
# 参数含义: # sd:存储定义。anchor 指定测试文件所在目录;size 指定在 anchor 下创建的文件大小 # wd:负载定义。sd 引用上面的存储;rdpct 是读百分比;seekpct 是随机比例 # rd:运行定义。wd 引用负载;iorate 是目标速率,max 表示不限制;elapsed 是运行秒数 # threads 是并发线程数;interval 是采样间隔(秒) sd=sd1,anchor=/tmp/vdb,size=4g,openflags=o_direct wd=wd1,sd=sd1,rdpct=70,seekpct=100,xfersize=4k rd=rd1,wd=wd1,iorate=max,elapsed=60,threads=16,interval=1把这段内容保存为test4k.conf,在 vdbench 目录下执行./vdbench -f test4k.conf,输出目录里会生成logfile.html、summary.html和errorlog.html三个文件。sd 里的openflags=o_direct很关键,它让 I/O 绕过操作系统缓存直接打到磁盘,否则压测结果会被 page cache 严重污染,尤其是测试文件不大时,第二次运行可能全命中缓存,IOPS 数字看起来高得离谱。
3.2 从顺序读测到稳态:参数如何逐项调
跑通最小示例之后,下一步是把参数拆开看每一项对结果的影响。rdpct控制读写比例,100 表示纯读,0 表示纯写;seekpct控制随机程度,100 是全随机,0 是全顺序;xfersize控制单次传输块大小,常见的组合是 4k 随机、64k 顺序、1M 大块。线程数和队列深度之间存在近似换算关系,在单线程异步 I/O 场景下,iorate设置为 max 时,实际并发深度约等于线程数乘以每次提交的 I/O 数量,但 vdbench 默认每次提交一个 I/O,所以线程数基本等于队列深度。
调参的正确姿势是「单变量法」。比如测一块 SSD 的稳态随机写性能,我会先固定xfersize=4k, rdpct=0, seekpct=100,然后把 threads 从 1、4、16、64 逐步拉升,每次跑满 300 秒。注意 vdbench 的预热机制:前几十秒硬件缓存和固件策略会显著影响数字,至少跑 120 秒再读稳态值。elapsed=300是秒数,如果做完整老化测试,常写成elapsed=3600,配合interval=10降低采样密度,避免生成超大日志。
block 大小的选择要和业务模型匹配。测数据库 Redo Log 场景用 512B 或 4K,测视频监控写入用 1M 顺序写,测文件服务器用混合大小。vdbench 支持用逗号分隔多个 xfersize,比如xfersize=4k,8k,16k,工具会按比例分配 I/O,但这种写法会让报告更难解读,除非确实需要模拟混合负载,否则建议一次测一种块大小。
4. 多机压测与数据校验:分布式工作负载的两个硬核用法
4.1 分布式压测的从机配置与启动顺序
单机压测只能体现一台服务器对存储的访问能力,真实生产环境往往是几十台虚拟机同时打一个存储阵列。vdbench 的分布式模式不需要额外安装 agent,而是通过在同一份配置里给 sd 加host=参数实现多机协同。每一台参与测试的机器都需要有 vdbench 的完整目录,主机通过 RMI 协议向从机下发配置并汇总结果。
# 假设有两台机器:master=192.168.1.10, slave1=192.168.1.11 # 在 master 上执行的配置(保存为 distributed.conf) sd=sd1,host=192.168.1.11,anchor=/tmp/vdb_mnt,size=8g,openflags=o_direct wd=wd1,sd=sd1,rdpct=0,seekpct=100,xfersize=4k rd=rd1,wd=wd1,iorate=max,elapsed=300,threads=32,interval=5 # 在 slave1 上先启动从机服务: ./vdbench -m 192.168.1.10 -n slave1 # 在 master 上启动分布式测试: ./vdbench -f distributed.conf这段配置的关键在启动顺序:必须先在所有从机上执行-m参数指定主机的 IP 并声明从机名,然后在主机上跑-f命令。如果从机没有先起来,主机会报Connection refused或No available slave。从机名-n可以随意取,但建议用有意义的标识,比如db-node-01,因为报告里会按从机名分组显示。主机和从机的 vdbench 版本必须完全一致,否则 native 库的接口对不上,表现是初始化阶段报RemoteException,这个坑极其隐蔽,因为错误信息不会明说版本不匹配,我遇到过两次,排查到最后才发现一台机器是 3.6 版一台是 3.7 版。
分布式模式下每个从机的 sd 定义是独立的,可以给不同从机配置不同的 anchor。比如三台机器分别挂载同一存储阵列的三个 LUN,就可以定义三个 sd 指向各自的路径。报告里每一台从机的 IOPS 和延迟会分开统计,同时有一个汇总行,这个汇总数字才是集群视角的真实性能。注意:如果测试的是网络存储(比如 iSCSI 或 NFS),多机同时打一个 LUN 时,存储端的控制器固件会成为瓶颈,报告里看到的延迟会明显劣化,这是正常现象,不代表测试配置有问题。
4.2 数据一致性校验:validate 参数与 data_errors 判定
纯性能压测只能告诉你「块设备能跑多快」,但存储系统在高压下可能发生静默数据损坏——写入的数据和读回的数据不一致。vdbench 在 rd 段里启用validate=yes后,会对每次写操作生成校验数据,并在读操作时对比。这个机制和 FIO 的 verify 模式对齐,但实现方式不同:FIO 在写入时插入特定模式的校验头,vdbench 则用数据生成器维护一份内存映像。
# 在 rd 段中启用数据验证,并设置校验间隔 rd=rd1,wd=wd1,iorate=max,elapsed=600,threads=16,interval=10,validate=yes,validate_percent=100validate_percent控制参与校验的 I/O 百分比,100 表示全部校验,适用于较短时间的存储完整性测试;如果做长时间性能测试又不想让校验开销影响吞吐,可以降到 5 或 10。启用校验后,测试结束后打开errorlog.html,重点看data_errors字段——非零代表发生数据不一致,需要定位是存储固件问题、线缆问题还是驱动问题。这个字段不显示在 summary 页面上,我在一开始总盯着 summary 看,直到一次真实的数据损坏事件才发现 errorlog 才是关键页面。
还要提醒一点:validate=yes要求测试区域必须是「干净」的,也就是 sd 定义的存储对象必须先格式化。vdbench 的做法是在 sd 段加format=yes,它会先对整个测试区域做一次全量写,确保校验映像是完整的。这个操作会覆盖目标分区上的所有数据,务必确认测试盘里没有需要保留的内容。常见的翻车场景是拿一块还存着旧数据的盘跑 validate,前几秒读到旧数据和校验映像不一致,报一堆 data_errors,吓得以为存储坏了。
5. 避坑记录:Java 版本、共享目录与不可复现的性能数字
5.1 ./vdbench 直接报 Java 命令找不到
现象:在 Rocky Linux 或 Ubuntu 上执行./vdbench -e,终端提示-bash: java: command not found,或者提示UnsupportedClassVersionError。
原因:前者是系统没装 Java 或者 PATH 没包含 Java 路径;后者是装了高版本 Java 而 vdbench 版本太老不支持。vdbench 3.x 对 Java 的版本敏感度很高,有的版本在 Java 11 下能跑,有的直接抛类加载异常。
解决:先执行java -version确认现有版本。如果是 17 或更高,建议直接装 1.8 以免后续出现莫名奇妙的报错;如果必须用高版本 Java,可以试试加-J-Djava.net.preferIPv4Stack=true参数避免分布式模式下的 IPv6 地址解析问题。血泪经验:不要在一开始为了省事沿用系统自带的 Java 11,遇到过太多「配置看起来没写错但一跑就崩」的情况,最后都归结到 Java 版本上。
5.2 sd 定义指向裸设备却报 Permission denied
现象:sd 里的 path/dev 指向/dev/sdb,跑测试时错误日志显示open() failed: Permission denied。
原因:vdbench 默认需要直接读写块设备,当前用户对/dev/sdb没有读写权限。更隐蔽的情况是测试文件创建在普通用户主目录下,但 anchor 路径指定的父目录权限受限。
解决:裸设备测试时把用户加入disk组或用 root 运行;文件测试时确保 anchor 目录的 owner 是当前用户。我一般会给专门的测试目录做字符集和权限检查:mkdir -p /tmp/vdb && chown -R $(whoami) /tmp/vdb。另外,openflags 里还可以加fsync=yes来让每个写操作都同步落盘,这会显著降低 IOPS 但能真实反映数据到达物理介质的时间,适合测写延迟敏感场景。
5.3 同样配置跑两次结果差一倍:缓存与未格式化
现象:同一份配置文件,间隔几分钟跑两次,第一次 IOPS 是 80000,第二次变成 150000,排除存储侧抖动还是差很多。
原因:第一次测试的数据部分还留在操作系统页缓存里,第二次读取命中了缓存。这是文件模式下最典型的「不可复现数字」来源,不是 vdbench 的随机性造成的。另一种情况是 sd 没有设置format=yes,第一次跑完后磁盘上的数据布局已经改变,第二次在不同位置写入导致性能差异。
解决:文件模式下,sd 里加openflags=o_direct强制绕过缓存;没有 o_direct 条件的环境,在测试前执行sync && echo 3 > /proc/sys/vm/drop_caches清缓存,但这要求 root 权限。裸设备模式没有缓存问题,所以生产环境压测尽量用裸设备。还有一个细节:format=yes会导致测试前有一段全量写盘的过程,这段时间不计入 elapsed,但会占掉很大一部分测试窗口,我通常在准备阶段单独跑一次 format 配置,正式测试配置里去掉 format 参数。
5.4 分布式测试启动后从机报 RemoteException
现象:master 上执行./vdbench -f distributed.conf后,终端报RemoteException: null或者slave not connected。
原因:最常见的是从机没有先启动./vdbench -m <master_ip> -n <slave_name>,或者 master 与从机的 vdbench 版本不一致。还把防火墙因素放进来——vdbench 分布式模式使用 RMI 动态端口,如果从机启用了 firewalld,即使主端口通了,动态端口也会被拦。
解决:确认从机已就绪并保持终端不关闭;用vdbench -e分别检查两边的版本号确保一致;防火墙至少要放行从机的 2000-3000 端口段,或者干脆把从机的 firewalld 临时关闭做连通性验证。验证连通性的动作要主动做,不要等报错再去查——telnet <slave_ip> 2000是判断网络是否通的最快方式。
5.5 报告里 response time 出现巨大尖峰但系统不忙
现象:logfile.html的延迟曲线里,99% 的采样点延迟在 1ms 以内,但某个采样间隔突然跳到 500ms,平均延迟被拉高。
原因:检查间隔内是否有其它进程抢占了磁盘或 CPU。vdbench 只负责产生 I/O 和记录数据,不会隔离系统上其它负载。常见干扰源:cron 定时任务、日志轮转、其它测试工具残留进程。
解决:压测前用htop和iostat -x 1观察系统状态,确保测试窗口内没有其它明显 I/O。如果延迟尖峰集中在某个目录,检查该目录是不是在慢速磁盘上——比如把 anchor 指向了 home 目录而 home 目录在 NAS 挂载上,性能和本地盘完全两回事。这个坑的本质是「测试环境不干净」,而不是 vdbench 配置问题,但数据一出来,背锅的永远是压测工具。
6. 报告解读与调参技巧:从 logfile.html 反推存储瓶颈
# 结果文件位置:执行 vdbench 的目录下自动生成 output/ 子目录 # 关键文件说明: # output/logfile.html 完整 I/O 日志,含每个采样点的 IOPS/带宽/延迟 # output/summary.html 汇总报告,按测试阶段分组 # output/errorlog.html 错误及数据校验失败记录读完一份报告只需看三块:IOPS、resp time的 avg 和 max 值、data_errors是否非零。但很多人忽略了一个有效参数——interval采样间隔。默认 1 秒采样会让 logfile.html 变得巨大,如果是 24 小时老化测试,日志文件能到几百 MB,打开就卡死浏览器。我跑长测时会把interval=10或interval=30,够看趋势且文件可管理。
一个值得掌握的调参思路是「从延迟反推队列深度」。如果报告显示 4k 随机读的 IOPS 稳定在 20000,延迟 1.5ms,那么平均队列深度约等于IOPS × 延迟(秒)= 20000 × 0.0015 = 30。这个值如果远超存储设备的队列深度规格,说明请求已经排到控制器缓冲区之外,再往上加线程只会增加延迟而不会提升吞吐——这时性能瓶颈不在磁盘而在协议栈或存储控制器。明白这个关系后,就不会盲目追求高线程数。
我个人习惯把 vdbench 和 FIO 做交叉验证:同一场景两种工具各跑一遍,对比 IOPS 和延迟趋势是否一致。两个工具的负载生成逻辑不同(FIO 是 C 编译的原生程序,vdbench 是 Java 调度加 native 库),数字本身不可能完全一样,但趋势和拐点应该吻合。如果 vdbench 报告的稳态 IOPS 明显低于 FIO 的一半,那往往是 vdbench 侧的参数没对齐,比如队列深度差异或 fsync 设置不同,先查配置再怀疑工具本身。有一次我发现 vdbench 的纯读测试结果只有 FIO 的三分之一,排查了好久才发现是 sd 里没写openflags=o_direct,I/O 全部走了页缓存。从那以后,我每次压测前都强制走一遍自查清单:确认裸设备路径、确认 o_direct、确认 validate 参数、确认 output 目录已清空。写配置不过一分钟,但少掉的那些重复排障时间,远比这一分钟值钱。希望这份拆解能帮你在存储压测的路上少踩几个我能踩到的坑。
本文还有配套的精品资源,点击获取