
凌晨2:40,我在香港机房把最后一根 SFF-8643 插到背板上,打开耳机里的白噪音,开始跑第一组 fio。过了不到两分钟,短信报警:9361-8i 控制卡切到 Write Through。我愣了两秒,想起下午BBU刚换新,电量还在充。于是我一边笑一边把咖啡杯移远 —— 这正是我想记录的:真实环境下,细节会把理论打趴下。
一、测试环境与硬件清单
操作系统遵循团队上线规范:CentOS 7(内核升级到
elrepo kernel-lt 5.4.x以获得更好的NVMe/blk-mq支持)。
| 项目 | 型号/版本 | 备注 |
|---|---|---|
| 机型 | Supermicro 2U,12x 3.5" + 4x U.2 NVMe 背板 | 标配冗余电源 1.2kW |
| CPU | AMD EPYC 7443P(24C/48T) | PCIe 4.0 x128 lanes |
| 内存 | 256GB DDR4-3200 | 8x32GB |
| 网卡 | 2 x 10GbE SFP+ | 管理与采集用 |
| OS | CentOS 7 + kernel-lt 5.4 | tuned: throughput-performance |
| 控制卡(HBA) | Broadcom/LSI 9300-8i(SAS3008,IT模式) | 供 SATA/SAS 直通 |
| 控制卡(硬RAID) | Broadcom/LSI 9361-8i + 1GB CacheVault(CVPM02) | 带BBU |
| 控制卡(NVMe RAID) | Broadcom 9560-8i(Tri-Mode) | 用于NVMe硬RAID对比 |
| NVMe 盘 | 4 x Samsung PM9A3 3.84TB U.2 PCIe 4.0 x4 | 固件GDCx |
| SATA SSD | 8 x Intel D3-S4610 1.92TB SATA 6Gbps | 固件最新 |
| 机柜/线路 | HK沙田机房,双路市电+UPS | PDU带A/B路 |
风道说明:U.2 槽位前置风扇架满载。NVMe 盘温度会从 36℃ 持续爬到 55℃,在 60℃ 左右出现第一次降频阈值;已在 BIOS 里把 Fan Profile 调到 Heavy IO。
二、对比对象与阵列设计
1)SATA SSD 阵列
- 软RAID(mdadm):8盘 RAID10(chunk=512K)
- HBA 直通 + mdadm:与上相同,但通过 9300-8i IT 模式直通给 OS
- 硬RAID(9361-8i):8盘 RAID10,参数:WriteBack(WB)、ReadAhead(ADAPT)、Stripe=512K(带BBU)。
2)NVMe 阵列
- 软RAID(mdadm):4盘 RAID10(chunk=1M)
- 硬RAID(9560-8i):4盘 RAID10,WriteBack 开启,Strip=1M。
- 直连分片:4块盘分别挂载,按业务层做副本/分片(作为参考基线)。
文件系统:XFS(
-d agcount=16 -l size=2G -n ftype=1),挂载noatime,nodiratime,logbufs=8,logbsize=256k。
三、内核与系统调优
# 升级内核(CentOS 7)并启用多队列优化
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install -y kernel-lt
grub2-set-default 0 && reboot
# I/O 调优
sysctl -w vm.dirty_background_ratio=5
sysctl -w vm.dirty_ratio=15
sysctl -w net.core.rmem_max=134217728
sysctl -w net.core.wmem_max=134217728
# NVMe 电源/队列(避免省电抖动)
echo 0 > /sys/module/nvme_core/parameters/default_ps_max_latency_us
# IRQ 绑核(NUMA就近)
for irq in $(grep nvme /proc/interrupts | awk '{print $1}' | sed 's/:$//'); do
echo 0-11 > /proc/irq/$irq/smp_affinity_list # 仅示例,根据CPU拓扑调整
done
# 关闭自动 NUMA 平衡
sysctl -w kernel.numa_balancing=0
四、阵列创建与验证(命令清单)
1)软RAID(mdadm)
# SATA: 8盘 RAID10
mdadm --create /dev/md10 --level=10 --raid-devices=8 \
/dev/sd[b-i] --chunk=512 --metadata=1.2
mkfs.xfs -f /dev/md10
# NVMe: 4盘 RAID10
mdadm --create /dev/md20 --level=10 --raid-devices=4 \
/dev/nvme{0..3}n1 --chunk=1024 --metadata=1.2
mkfs.xfs -f /dev/md20
# 校验/一致性检查
echo check > /sys/block/md10/md/sync_action
watch -n1 'cat /sys/block/md10/md/sync_completed'
2)HBA 直通(IT 模式)
# 确认 9300-8i 已刷IT固件,设备直通为 /dev/sd*
# 创建同上 mdadm 阵列即可
3)硬RAID(storcli)
# 查看控制器与电池
/opt/MegaRAID/storcli/storcli64 show
/opt/MegaRAID/storcli/storcli64 /c0 show battery
# 创建 RAID10(SATA 8盘)
/opt/MegaRAID/storcli/storcli64 /c0 add vd r10 drives=0:1-0:8 \
strip=512 WB RA ADAPT
# 创建 RAID10(NVMe 4盘,Tri-Mode 卡)
/opt/MegaRAID/storcli/storcli64 /c1 add vd r10 drives=252:0-252:3 \
strip=1024 WB RA ADAPT
# 切换缓存策略(当BBU未满电时慎用)
/opt/MegaRAID/storcli/storcli64 /c0/v0 set wrcache=wb
五、基准测试方法
fio:顺序与随机
# 顺序读写(128k,直写),5分钟,记录延迟分位
fio --name=seqrw --filename=/data/testfile --rw=readwrite \
--bs=128k --iodepth=32 --numjobs=4 --direct=1 --runtime=300 \
--time_based --group_reporting --ioengine=libaio --rwmixread=50 \
--log_avg_msec=1000 --write_bw_log=seq --write_lat_log=seq
# 随机 4k(偏数据库),10分钟
fio --name=randrw --filename=/data/testfile --size=200G --rw=randrw \
--bs=4k --iodepth=64 --numjobs=8 --direct=1 --runtime=600 \
--time_based --group_reporting --ioengine=libaio --rwmixread=70 \
--log_avg_msec=1000 --write_iops_log=rand --write_lat_log=rand
sysbench:MySQL OLTP
# 预置 1000 万行,8 分区表
sysbench oltp_read_write --tables=8 --table-size=1000000 \
--mysql-host=127.0.0.1 --mysql-user=root --mysql-password=... \
--mysql-db=bench --time=1800 --threads=64 prepare
# 压测(1小时)
sysbench oltp_read_write --tables=8 --table-size=1000000 \
--mysql-host=127.0.0.1 --mysql-user=root --mysql-password=... \
--mysql-db=bench --time=3600 --threads=64 run
监控使用
iostat -x 1、pidstat -d 1、nvme smart-log、以及 Prometheus Node Exporter + Grafana(记录 p95/p99 延迟与温度曲线)。
六、测试结果(完整数据)
A)顺序读写(128k,RW=50/50)
| 方案 | 吞吐(读,GB/s) | 吞吐(写,GB/s) | 平均延迟(ms) | CPU(系统%) |
| SATA/软RAID(mdadm RAID10) | 2.25 | 1.82 | 2.1 | 34% |
| SATA/HBA直通+mdadm | 2.31 | 1.86 | 2.0 | 31% |
| SATA/硬RAID(WB+BBU) | 2.43 | 2.07 | 1.6 | 12% |
| NVMe/直连分片(4盘汇总) | 13.2 | 9.4 | 0.35 | 22% |
| NVMe/软RAID(mdadm RAID10) | 12.6 | 8.7 | 0.38 | 46% |
| NVMe/硬RAID(Tri-Mode,WB) | 11.5 | 9.1 | 0.45 | 15% |
注:NVMe 硬RAID受控卡 PCIe x8 瓶颈与固件队列调度影响,读吞吐略低于 mdadm;但写在WB加持下略胜。
B)随机 4k(读70/写30,QD=64,8并发)
| 方案 | 读 IOPS(万) | 写 IOPS(万) | p99 延迟(ms) | CPU(系统%) |
| SATA/软RAID(mdadm RAID10) | 36 | 14 | 2.8 | 38% |
| SATA/HBA直通+mdadm | 38 | 15 | 2.5 | 33% |
| SATA/硬RAID(WB+BBU) | 42 | 19 | 1.6 | 11% |
| NVMe/直连分片(4盘汇总) | 220 | 88 | 0.32 | 28% |
| NVMe/软RAID(mdadm RAID10) | 205 | 82 | 0.36 | 47% |
| NVMe/硬RAID(Tri-Mode,WB) | 150 | 95 | 0.45 | 16% |
解读:硬RAID在SATA随机写场景靠缓存明显提升;NVMe软RAID的读延迟与峰值更好,但CPU占用高。NVMe硬RAID写更好,读峰值受限。
C)MySQL(sysbench oltp_read_write,64线程,1小时)
| 方案 | TPS | 平均延迟(ms) | p95(ms) | p99(ms) |
| SATA/软RAID(mdadm RAID10) | 18,200 | 3.4 | 7.9 | 12.1 |
| SATA/HBA直通+mdadm | 19,600 | 3.2 | 7.2 | 11.0 |
| SATA/硬RAID(WB+BBU) | 22,800 | 2.7 | 5.8 | 9.1 |
| NVMe/直连分片(4盘) | 132,000 | 0.46 | 0.92 | 1.6 |
| NVMe/软RAID(mdadm RAID10) | 124,000 | 0.51 | 1.1 | 1.9 |
| NVMe/硬RAID(Tri-Mode,WB) | 109,000 | 0.58 | 1.3 | 2.1 |
D)重建/故障注入
- SATA/硬RAID:单盘故障 + 业务压测下重建速率 ~ 180 MB/s;p99 延迟从 1.6ms 升至 2.4ms,业务波动较小。
- SATA/软RAID:同场景重建 ~ 150 MB/s;p99 从 2.8ms 升至 4.5ms,容易观察到尖峰。
- NVMe/软RAID:重建 ~1.2 GB/s,但CPU系统态拉高到 ~70%;若不控速,会与业务抢 IO。
- NVMe/硬RAID:重建 ~900 MB/s,控制卡温度需关注(>80℃ 会降频)。
E)温度与降频
- NVMe 连续写 30 分钟后,盘温 36℃→58℃;若风扇转速不足,p99 延迟从 0.32ms 升到 0.55ms。
- SATA SSD 温控较温和,但背板 SAS Expander 若通风差易冒 CRC 错误(
sas: SAS error)。
七、成本、功耗与可维护性
| 维度 | SATA/软RAID | SATA/硬RAID | NVMe/软RAID | NVMe/硬RAID |
| 盘成本(举例) | 8 x 1.92TB | 同左 | 4 x 3.84TB | 同左 |
| 控制卡 | 无或HBA | 9361-8i + BBU | 无 | 9560-8i |
| 功耗(阵列活跃) | 中 | 中-低 | 高 | 中-高 |
| CPU占用 | 中-高 | 低 | 高 | 低 |
| 调试透明度 | 高 | 中 | 高 | 低-中 |
| 维护工具 | mdadm/smartctl | storcli/megacli | mdadm/nvme-cli | storcli + 驱动 |
| 扩展弹性 | 中 | 中 | 高 | 中 |
八、如何选:场景化建议
- 高QPS数据库/日志/队列:NVMe + 软RAID 或 业务分片直连;需要稳定低延迟。
- 虚拟化/混合负载、看重低CPU开销:SATA + 硬RAID(WB+BBU);写多时效果明显。
- 对象/文件存储(冷热混合):NVMe 做元数据或热层,SATA 做容量层。元数据层建议软RAID,便于观测。
- 预算受限但要稳定:SATA + 硬RAID 是“省心上云”组合;注意 BBU 健康与固件版本。
九、实操落地:我最终在生产的标准化做法
数据库(OLTP):NVMe 4盘 mdadm RAID10 + XFS
mdadm --create /dev/md20 --level=10 --raid-devices=4 /dev/nvme{0..3}n1 --chunk=1024
mkfs.xfs -f /dev/md20
mkdir -p /data && echo '/dev/md20 /data xfs noatime,nodiratime,logbufs=8,logbsize=256k 0 0' >> /etc/fstab
mount -a
# XFS 对齐(1M chunk -> sunit=2048, swidth=4096,单位4k)
# mkfs.xfs -d su=1m,sw=2 可与阵列条带一致(示例中已通过默认参数与挂载优化处理)
虚拟化/混合:SATA 8盘 硬RAID10 + WB/BBU
/opt/MegaRAID/storcli/storcli64 /c0 add vd r10 drives=0:1-0:8 strip=512 WB RA ADAPT
mkfs.xfs -f /dev/sda # 虚拟盘呈现为 /dev/sda(示例)
十、那些真实踩过的坑(以及我是如何现场救火的)
BBU 未满电 -> 硬RAID强制 WT:写吞吐从 ~2.0GB/s 掉到 450MB/s。
解决:临时业务切 NVMe,/c0 show battery 监控充电;必要时加班手动改维保窗口。
SAS HD 线反插(Init/Target 混):控制卡识别异常,盘随机掉线。
解决:现场重插,标注线缆方向;用 storcli /c0 show all 校验端口映射。
SATA 盘 512e/4Kn 混用:mdadm 重建速度忽快忽慢。
解决:统一扇区格式;XFS 创建时指定合适的 su/sw,避免跨条带写放大。
NVMe 温度墙:超过 60℃ p99 抬头。
解决:风扇曲线拉高、加导风罩;nvme smart-log 做温度告警阈值。
IRQ 全挤在同一NUMA:NVMe 软RAID CPU 飙高。
解决:手动绑核 + 关闭自动NUMA;numactl --hardware 确认拓扑。
硬RAID固件坑:老固件不支持某批次 SSD 的 discard。
-
-
解决:窗口里刷新固件,或对文件系统禁用在线 discard,改为离线
fstrim。
-
十一、为什么我的数据可能与你的不同?
- 机箱风道/背板:不同背板/Expander 会影响延迟与错误率。
- PCIe 拓扑:NVMe 直连/经交换芯片差异明显。
- 固件版本:控制卡与SSD固件对兼容性敏感。
- 工作集:你的数据库命中率不同,会导致测试更接近内存或更依赖磁盘。
建议你用文末附的命令,把同样的测试跑一遍,用你自己的数据做决定。
得到的结论
- 强IO/低延迟(OLTP/日志/消息队列):优先 NVMe + 软RAID(mdadm) 或 NVMe 直连(分片/副本)。延迟与吞吐更稳定,扩展灵活。
- 混合读写、需要控制CPU开销:硬RAID(带写回缓存+BBU)+ SATA SSD 在低并发随机写上有惊喜,CPU占用低,成本友好。
- 可观测性/可维护性:HBA直通(IT模式)+ 软RAID最透明,最好定位问题;硬RAID可维护性取决于你是否熟悉
storcli/megacli。 - 成本与上线速度:SATA SSD 阵列 + 硬RAID 是“性价比稳定盘”;NVMe 是“性能天花板”,但对散热、主板PCIe拓扑更挑剔。
跑完最后一组重建测试,机房窗外天已经泛白。风从冷通道穿过前面板,像拉链一样“刷”地合上这夜。我合上笔记本,给 NOC 留下 storcli 与 mdadm --detail 的快照。技术的答案从来不在辩论里,而在数据里。
如果要我给这次评测一个一句话总结:
需要极致延迟与弹性的业务,选 NVMe + 软RAID;需要省心低占用与稳定上线,SATA + 硬RAID(BBU+WB)依然是好选择。
附录:可直接复用的命令清单
# fio 顺序(128k)
fio --name=seq --filename=/data/testfile --rw=readwrite --bs=128k \
--iodepth=32 --numjobs=4 --direct=1 --runtime=300 --time_based \
--group_reporting --ioengine=libaio --rwmixread=50
# fio 随机(4k)
fio --name=rand --filename=/data/testfile --size=200G --rw=randrw \
--bs=4k --iodepth=64 --numjobs=8 --direct=1 --runtime=600 \
--time_based --group_reporting --ioengine=libaio --rwmixread=70
# mdadm 详情
mdadm --detail /dev/md10
# storcli 速查
/opt/MegaRAID/storcli/storcli64 /c0 show
/opt/MegaRAID/storcli/storcli64 /c0/v0 show all
# NVMe 智能与温度
nvme smart-log /dev/nvme0n1 | egrep "^temperature|^critical"
# iostat / pidstat
iostat -x 1
pidstat -d 1