高速磁盘阵列在数据库、虚拟化、备份和媒体制作场景里很常见,但要给它做一次可信的性能评估,并不比部署一套应用系统简单。很多人把“测试”理解成堆几块盘、建一个卷,然后跑一次跑分工具。结果漂亮就认为阵列性能没问题,结果不理想就怀疑某一块盘出了问题。这种测试思路最大的问题是不可复现,也难定位瓶颈。磁盘阵列真正的性能边界,取决于盘、控制器、缓存、条带策略、后端链路和应用 IO 模型共同作用的结果。
为了便于描述,后文把被测对象统一记作 AZ3。AZ3 不是某个厂商的特定型号,只是一台用于演示的高速磁盘阵列测试设备代号。你在自己的环境中,只需要把控制器编号、设备路径、盘槽和逻辑卷名称替换成真实值,方法与本文流程保持一致。下面的内容会围绕“硬件状态核实 -> 测试卷搭建 -> fio 负载设计 -> 结果分析 -> 异常排查 -> 生产部署”这条链路展开,目标是让一次阵列性能测试具有可复现性和可比较性。
1. 高速磁盘阵列的性能边界,先于测试命令确定
1.1 从单盘到应用,中间至少隔着四层
很多新手会先看硬盘单盘型号,然后预期整阵列也能达到差不多的速度。实际并不是这样。从硬盘到业务应用,至少经过四层:
- 存储介质层:机械盘受转速和寻道限制,固态盘受闪存颗粒和垃圾回收影响。单盘的顺序读、随机读、随机写能力差异极大。
- RAID 控制器层:控制器负责条带化、镜像、奇偶校验、缓存调度、坏块处理。控制器的 CPU 主频、缓存容量、缓存策略和固件逻辑会直接影响最终 IO 表现。
- 链路和背板层:盘插在背板上,由线缆或 SAS Expander 连到控制器。链路协商速率下降、线缆松动、背板端口故障,都会让单盘性能被压住。
- 应用 IO 模型层:同样是这台阵列,跑 1MiB 连续大文件与跑 4KiB 随机小事务,测出来的指标是两个方向。前者看吞吐,后者看 IOPS 和延迟分布。
所以,高速磁盘阵列的性能测试不能只讨论“这块盘快不快”,而要看“当前这套完整链路能不能支撑目标负载”。AZ3 在测试前同样要检查这四层,否则后面任何数字都缺少解释上下文。
1.2 RAID 级别决定容量、冗余和写入惩罚
测试卷搭建之前,先确认测试使用哪种 RAID 级别。RAID 级别不仅影响可用容量,还决定随机写路径上的额外开销。
| RAID 级别 | 最少盘数 | 可用容量 | 允许故障盘数 | 随机写特点 | 典型场景 |
|---|---|---|---|---|---|
| RAID 0 | 2 | 全部容量 | 0 | 无校验开销 | 强调吞吐、可牺牲冗余 |
| RAID 1 | 2 | 单盘容量 | 1 | 同一数据写两份 | 系统盘、日志盘 |
| RAID 5 | 3 | 约 (N-1)/N | 1 | 写校验需要读改写 | 读多写少场景 |
| RAID 6 | 4 | 约 (N-2)/N | 2 | 双重校验,写开销更大 | 大容量、担心重建风险 |
| RAID 10 | 4 | 一半容量 | 每组镜像坏一块 | 镜像写,读可分流 | 数据库、虚拟化等核心业务 |
RAID 5 和 RAID 6 在连续读场景下表现不错,但面对高并发随机写时,奇偶校验计算和读改写惩罚会比较明显。如果测试目的是验证数据库事务盘的极限能力,用 RAID 10 会更容易观察到介质和控制器本身的瓶颈;如果测试目的就是大容量归档存储,RAID 6 更贴近真实部署。测试卷的 RAID 级别要和最终生产卷一致,否则测试数据没有迁移参考价值。
1.3 先定义测试目标,再选择负载参数
测试命令不是越复杂越好。AZ3 第一次做性能基线时,可以先分成三类负载:
- 顺序大块读写,测试连续吞吐能力,块大小建议 128KiB 到 1MiB。
- 小块随机读写,测试事务类 IO 性能,块大小通常用 4KiB 或 8KiB。
- 混合负载,模拟数据库或虚拟化业务中的读写比例,可以通过 fio 的
rwmixread等参数控制。
如果看到测试结果异常,不要立刻认为阵列坏了。先回答一个问题:这次测试到底想看什么?如果只是想验证备份链路,那随机 4K 成绩低并不能说明阵列有问题;如果目标是数据库存储,那顺序读写跑得再高也不能代表事务 IO 一定好。测试目标和负载参数不对齐,是磁盘阵列性能报告中最常见也最容易被忽略的错误。
2. 不要直接跑工具,先把硬件和固件状态核实清楚
2.1 测试前要记录的环境信息
高速磁盘阵列的测试结果容易受环境因素干扰。AZ3 在开始测试前,至少要把下面几类信息记录下来,形成一份环境基线。
| 检查对象 | 需要记录的信息 | 检查原因 |
|---|---|---|
| 盘槽与背板 | 盘插在哪个槽位,背板端口编号 | 后续更换硬盘时能定位盘位 |
| 硬盘型号 | 容量、接口类型、转速或介质类型 | 不同盘混插会影响阵列总性能 |
| 硬盘固件 | 固件版本 | 个别固件版本可能存在特定问题 |
| 控制器固件 | 控制器固件版本 | 旧固件可能缺少已知修复 |
| 驱动版本 | HBA 或 RAID 卡驱动版本 | 驱动与内核版本不匹配会导致异常 |
| 缓存状态 | 缓存容量、读写百分比、掉电保护状态 | 写缓存不可保护时不能开启 write-back |
| 逻辑卷配置 | RAID 级别、条带大小、卷名称 | 确认测试卷是独立卷,不承载业务 |
| 链路速率 | SAS 或 SATA 协商速率是否正常 | 协商速率下降会限制单盘吞吐 |
这些信息可以用文本记录,也可以保存为一张简单的环境清单。真实项目里,性能问题往往发生在更换硬盘、升级固件或者调整缓存策略之后。没有本次环境基线,后面做对比时很难找到变量。
2.2 用管理命令查看控制器、物理盘和卷状态
在 Linux 环境下,不同厂商的硬件 RAID 卡管理命令不同。以常见的部分硬件 RAID 卡为例,可以通过类似下面的命令查看控制器状态:
storcli /c0 show这条命令会输出控制器编号、固件版本、缓存保护状态、物理盘数量、逻辑卷数量等信息。不同版本的 storcli 输出字段会有差异,但一般都能看到:
- Controller Status
- Boot Drive
- Firmware Version
- JBOD / RAID 模式
- 逻辑卷列表
- 物理盘列表
查看物理盘状态可以使用:
storcli /c0 /eall /sall show某些控制器版本会显示每个盘槽的位置、型号、容量、固件状态和 S.M.A.R.T. 状态。重点看UGood、Onln、DHS这些状态。如果看到Degraded、Offline、Rebuild等关键字,需要先处理完再测试。
如果是软件 RAID 环境,可以用 mdadm 查看:
mdadm --detail /dev/md0 cat /proc/mdstat/proc/mdstat是最快的状态入口。如果出现[UU_U]或resync字样,说明卷处于降级或重建状态。这时候无论如何都不适合做性能测试,因为重建本身会持续占用 IO,结果不具备参考价值。
2.3 用系统日志排除已经存在的故障
控制器管理命令能看到当前状态,但偶发性错误往往要翻系统日志。测试前可以先执行:
dmesg -T | tail -n 200 dmesg -T | grep -i -E "sd[a-z]|sas|scsi|megaraid|mpt3sas" | tail -n 200 grep -i -E "error|fail|reset|rebuild|degraded" /var/log/messages | tail -n 200这些命令的目的不是逐行读懂,而是快速判断是否存在:
- 硬盘 IO 超时
- 控制器 reset
- SAS 链路复位
- 单盘离线或重建记录
- S.M.A.R.T. 错误
如果日志里大量出现reset或timeout,即使当前阵列状态是正常,也可能说明链路或硬盘存在间歇性故障。忽略这些日志直接跑性能测试,结果会忽高忽低,而且很难判断原因。
2.4 测试开始前必须确认的几条环境约束
测试卷不能存业务数据。这是最基本的红线,因为后续 fio 写测试会真实覆盖逻辑卷上的数据块。
如果阵列处于降级或正在重建,要先把故障盘处理完,等重建结束再测试。重建中的随机写负载会让测试成绩明显偏低,也容易掩盖新盘的性能问题。
如果控制器检测到缓存掉电保护异常,不要开启 write-back 写缓存策略。没有掉电保护时,write-back 只是把数据暂存在内存里,测试成绩会很好看,但生产环境中一旦断电,数据一致性和完整性都无法保证。
如果同一台存储服务器上有备份任务、定时快照、系统更新或数据迁移任务,需要先确认这些任务窗口。AZ3 的测试过程中,后台任务哪怕只占用一小部分 IO,也会让延迟指标出现毛刺。
注意:下面出现的创建 RAID、格式化文件系统和 fio 写测试命令,都会对目标设备和数据产生不可逆影响。学习时建议使用独立实验机或虚拟机磁盘,生产环境绝不能边看教程边复制命令。
3. 创建一块最小测试卷,同时验证 RAID 配置约束
3.1 为什么优先用 RAID 10 做测试卷
对于大多数需要同时观察性能和冗余的场景,RAID 10 是更好的起点。它把数据先做镜像,再在镜像组之间做条带化,读请求可以从多块盘中并行完成,写请求要写两份镜像盘。相比 RAID 5/6,RAID 10 的随机写路径更简单,更能反映控制器和磁盘介质本身的能力。
RAID 10 需要至少四块盘,可用容量是一半。如果测试盘总数不足,或者测试目标是视频归档之类的连续写场景,也可以改用 RAID 5 或 RAID 6。关键是测试卷的 RAID 级别必须和你计划部署的场景一致,否则测出来的性能基线没有参考意义。
3.2 硬件 RAID 卡上创建逻辑卷的示例
硬件 RAID 卡创建逻辑卷的命令强烈依赖厂商。下面命令只用于展示结构,不是所有型号都能直接执行:
# 伪命令行格式,具体要参考阵列卡对应的 storcli / megacli 文档 storcli /c0 add vd type=raid10 drive=0,1,2,3 size=all在真实控制器上,drive参数通常要写“控制器 ID + 盘槽 ID”,例如252:0这种格式,而且不同版本之间可能有差异。执行前先用storcli /c0 /eall /sall show确认盘位编号,避免选错盘。
创建逻辑卷之后,系统可能出现新的块设备,例如/dev/sdb或/dev/sdc。你可以用lsblk查看:
lsblk如果新增卷容量与预期不一致,先不要继续操作,回头检查 RAID 组中的盘数、盘容量和 RAID 级别是否选错。
3.3 软件 RAID 上创建测试卷的示例
如果实验环境没有硬件 RAID 卡,使用 Linux mdadm 也能搭建软件 RAID 10。下面的命令假设四块盘分别对应/dev/sdb、/dev/sdc、/dev/sdd、/dev/sde,并且这些盘已经清空、不包含业务数据:
mdadm --create /dev/md0 --metadata=1.2 --level=10 --raid-devices=4 --chunk=64 /dev/sdb /dev/sdc /dev/sdd /dev/sde--chunk=64表示条带块大小是 64KiB。chunk 越大,连续读时单个请求越容易落在同一块盘上,越小则单次大 IO 越会被拆散到更多盘上。具体选多少要和业务 IO 块大小配合,没有绝对最优值。
创建之后立刻查看状态:
cat /proc/mdstat多数软件 RAID 在创建后会执行后台恢复或初始化。如果/proc/mdstat显示resync进度,要等它完成再测试,否则读放大和写放大都会影响结果。
3.4 测试卷准备好之后,必须做四项核验
创建完 RAID 卷不要急着跑 fio,按下面四步核对:
- 容量是否符合预期。RAID 10 的可用容量是参与盘总容量的一半,如果结果不对,重新检查盘数与 RAID 级别。
- 卷状态是否为 healthy。硬件 RAID 看控制器状态,软件 RAID 看
/proc/mdstat。 - 条带或 chunk 大小是否记录。改变这一项会改变性能表现。
- 卷是否被文件系统自动挂载。如果后续要直接对裸设备测试,必须确保卷没有被挂载;如果要在文件系统上做应用模拟,则需要先格式化并挂载。
如果要在测试卷上建文件系统,可以执行:
mkfs.xfs -f /dev/md0 mkdir -p /mnt/mdtest mount /dev/md0 /mnt/mdtest是否使用文件系统,会影响测试结果的语义。裸设备测试更接近阵列本身能力,文件系统测试则包含文件系统分配、日志和缓存等开销。两种结果不能混在一起比较。
4. 用 fio 把顺序、随机和混合负载分开测量
4.1 安装 fio 并选择测试目标设备
fio 是磁盘性能测试中最常用的工具之一。在多数 Linux 发行版上可以用包管理工具安装:
apt install fio # 或 yum install fio安装完成后,先确认 fio 版本,避免不同版本之间存在参数差异:
fio --version接下来的测试命令以裸设备/dev/md0为例。如果测试卷已经挂载到/mnt/mdtest,直接打开裸设备可能会报Device or resource busy。需要先执行:
umount /mnt/mdtest写测试会在指定设备上写入数据。执行前再一次确认,
/dev/md0是专用测试卷,而不是系统盘、启动分区或包含业务数据的卷。
4.2 顺序读和顺序写测试
顺序读测试,观察连续读取吞吐能力。这里用 1MiB 块大小,深度设为 32,运行 60 秒:
fio --name=seq-read \ --filename=/dev/md0 \ --ioengine=libaio \ --direct=1 \ --rw=read \ --bs=1m \ --iodepth=32 \ --numjobs=1 \ --size=8g \ --runtime=60 \ --time_based \ --ramp_time=10 \ --group_reporting顺序写测试和读测试几乎一样,只是把--rw=read改成--rw=write:
fio --name=seq-write \ --filename=/dev/md0 \ --ioengine=libaio \ --direct=1 \ --rw=write \ --bs=1m \ --iodepth=32 \