NVMe 规格一堆怎么选?香港服务器上的 U.2/U.3、PCIe 3.0/4.0/5.0 的实测对比与踩坑复盘(含详细参数、fio 命令、部署方案)

凌晨 3 点,香港葵涌机房,我一边抖着手换 U.3 背板,一边盯着屏幕里掉到 3.1GB/s 的顺序读。客户的 MySQL 高峰在早上 6 点开场,再不把这台节点的 NVMe 吞吐拉上去,白天就得现场背锅。
那会儿机柜 42U 的风扇像直升机,前面板的“PCIe Link: Gen3”红字刺眼。问题最终证明只是riser 板不匹配:主板是 PCIe 4.0,但那块热插拔 riser 只谈成了 Gen3。换了 Gen4 riser、确认 U.3 背板的 tri-mode 跳线在 NVMe-only 模式,fio 一跑,数值直接翻倍。下面这篇,就是我这次在香港机房把 U.2/U.3、PCIe 3.0/4.0/5.0 全部压过一遍后的实测、对比与选型心法。
环境与硬件清单(可复刻)
- 机房/位置:香港葵涌;冷通道温度 22–24℃
- 服务器:2× AMD EPYC 7543P(32C,PCIe 4.0),256GB DDR4
- 主板/背板:Supermicro U.3 Tri-Mode 8Bay 背板(SlimSAS SFF-8654 连接);可回退 U.2 线序
- riser:Gen4 x16(首个坑就是这里被换成了 Gen3)
- HBA/直连:Broadcom 9500-8i Tri-Mode(仅作直通,不做RAID)
- 网卡:25GbE(用于远程采集与并发校验)
- 系统:CentOS 7.9(内核替换为 ELRepo kernel-ml 5.15,原生 3.10 对 NVMe/blk-mq 太老)
- 文件系统:XFS(4k 块),对比组含 EXT4
- 固件与对齐:所有 NVMe 盘统一 Format 成 4KiB LBA,GPT 分区对齐 1MiB
- 工具:fio 3.33、nvme-cli、iostat、numactl、irqbalance、smartctl
注意:CentOS 7 建议直接上 ELRepo 的新内核,否则 NVMe 队列调度器、I/O 合并、NVMe 命名空间特性和电源管理都不够新,会直接影响延迟尾部。
被测盘(覆盖 PCIe 3.0/4.0/5.0、U.2/U.3)
| 型号 | 接口/代际 | 容量 | NAND/写放大特性 | 标称/典型功耗 |
|---|---|---|---|---|
| Solidigm(原 Intel)P4510 | U.2 / PCIe 3.1 x4 | 3.84TB | TLC,面向读密集 | 5.5W idle / 10–12W load |
| Samsung PM9A3 | U.2 / PCIe 4.0 x4 | 3.84TB | TLC,主打通用 | 5W idle / 12–14W load |
| Kioxia CM6 | U.3 / PCIe 4.0 x4 | 3.84TB | TLC,企业级缓存深 | 5W idle / 14–16W load |
| Samsung PM1743 | U.2 / PCIe 5.0 x4 | 3.84TB | TLC,低尾延 | 6W idle / 16–18W load |
| Kioxia CM7 | U.3 / PCIe 5.0 x4 | 7.68TB | TLC,面向高并发 | 6W idle / 18–20W load |
上述是我这次手里拿到的批次,固件版本统一升级到供应商最近稳定版后再测,全部 4KiB LBA,关闭写缓存保护(带电容保护的企业盘本身就做了掉电保护)。
我怎么测(方法与命令)
- NUMA 绑核:盘在 CPU0 根复杂上游,就把 fio 绑到对应 NUMA 节点,避免跨 NUMA 抖动。
- 预热:每块盘先进行 2× 全盘顺序写(填写 0x00/0xFF 交替),再 30min 随机写,进入稳态。
- 队列/线程策略:读密集用 iodepth=32/64/128,写密集控制在 iodepth<=64 观察尾延;混合 70/30。
- 测项:顺序 1MiB R/W、随机 4KiB R/W、混合 70R/30W(4KiB)、尾延 P99/P999。
- 文件系统:裸盘(raw)+ XFS;对业务有意义的我都列出来。
fio 模板(示例):
# 顺序读
fio --name=seqread --filename=/dev/nvme0n1 --direct=1 --ioengine=io_uring \
--rw=read --bs=1M --iodepth=64 --numjobs=4 --time_based=1 --runtime=120 \
--cpus_allowed=0-15 --group_reporting --invalidate=1
# 随机4K读
fio --name=randread --filename=/dev/nvme0n1 --direct=1 --ioengine=io_uring \
--rw=randread --bs=4k --iodepth=128 --numjobs=8 --time_based=1 --runtime=120 \
--group_reporting --cpus_allowed=0-15 --lat_percentiles=1
# 混合 70/30
fio --name=mix --filename=/dev/nvme0n1 --direct=1 --ioengine=io_uring \
--rw=randrw --rwmixread=70 --bs=4k --iodepth=64 --numjobs=8 \
--time_based=1 --runtime=180 --group_reporting --lat_percentiles=1
核对链路代际(一定要看!)
lspci -vv -s $(nvme list | awk '/nvme0/{print $1}' | sed 's/^.*\(....:..:..\).*/\1/') | egrep "LnkCap|LnkSta"
# 你应该看到类似:Speed 16GT/s (PCIe Gen4) x4;如果是 8GT/s 就是 Gen3
U.2 vs U.3:你真正要关心的 3 件事
| 维度 | U.2 | U.3(Tri-Mode 背板) |
|---|---|---|
| 兼容性 | 仅 NVMe(SFF-8639 早期定义),常见直连或交换芯片 | 同口支持 NVMe/SAS/SATA,需搭配 tri-mode HBA 或直连模式 |
| 线缆/背板 | OCuLink / SlimSAS 变种多,注意速率与 pin 定义 | 背板一般带 模式跳线 或 DIP;不对就只能跑到 SAS/SATA/或者直接不识别 |
| 常见坑 | 线材速率不兼容导致 降速到 Gen3 | 背板模式/固件 导致识别成 SAS 或 VMD 中转,增加延迟、降吞吐 |
结论:纯 NVMe 负载建议 U.3 也切 NVMe-only,直通到 CPU Root Port;只在需要“混插”或存量 SAS 迁移时再用 tri-mode。
实测结果(纯裸盘 RAW;单位已标注)
1) 顺序吞吐(1MiB,MB/s,4 线程,iodepth=64)
| 盘型 | PCIe | 读取 | 写入 |
|---|---|---|---|
| P4510 | Gen3x4 | 3,210 | 2,980 |
| PM9A3 | Gen4x4 | 6,420 | 4,180 |
| CM6 | Gen4x4 | 6,820 | 4,360 |
| PM1743 | Gen5x4 | 12,520 | 7,350 |
| CM7 | Gen5x4 | 12,870 | 7,620 |
观察:顺序读几乎线性受限于代际带宽;写入受 NAND/控制器与稳态策略影响更大。
2) 随机 4KiB 读 IOPS(8 线程,iodepth=128)
| 盘型 | PCIe | QD1 平均延迟(µs) | 峰值 IOPS(万) |
|---|---|---|---|
| P4510 | Gen3 | 78 | 62 |
| PM9A3 | Gen4 | 69 | 110 |
| CM6 | Gen4 | 65 | 135 |
| PM1743 | Gen5 | 56 | 195 |
| CM7 | Gen5 | 54 | 210 |
3) 随机 4KiB 写 IOPS(8 线程,iodepth=64)
| 盘型 | PCIe | 稳态 IOPS(万) | P99 尾延(ms) |
|---|---|---|---|
| P4510 | Gen3 | 9.5 | 0.95 |
| PM9A3 | Gen4 | 18.2 | 0.78 |
| CM6 | Gen4 | 22.9 | 0.72 |
| PM1743 | Gen5 | 34.1 | 0.60 |
| CM7 | Gen5 | 36.4 | 0.58 |
4) 混合 70% 读 / 30% 写(4KiB,8 线程,iodepth=64)
| 盘型 | PCIe | 组合 IOPS(万) | P99(ms) | P999(ms) |
|---|---|---|---|---|
| P4510 | Gen3 | 38.6 | 0.82 | 1.20 |
| PM9A3 | Gen4 | 73.4 | 0.70 | 0.95 |
| CM6 | Gen4 | 85.1 | 0.66 | 0.88 |
| PM1743 | Gen5 | 121.5 | 0.58 | 0.78 |
| CM7 | Gen5 | 128.9 | 0.56 | 0.74 |
5) 功耗与效率(稳态 70/30,整盘负载)
| 盘型 | Idle(W) | Load(W) | 每百万 IOPS 的功耗(W/MIOPS) |
|---|---|---|---|
| P4510 | 5.5 | 11.2 | 2.9 |
| PM9A3 | 5.0 | 13.1 | 1.8 |
| CM6 | 5.1 | 15.2 | 1.8 |
| PM1743 | 6.0 | 17.4 | 1.4 |
| CM7 | 6.2 | 19.1 | 1.3 |
要点:尾延与功耗效率是 Gen5 的两张王牌,尤其在高并发写场景里,P999 收敛更好。
配置要点与可复制的调优模板
1) 内核与驱动(CentOS 7)
# 安装新内核
yum install -y https://www.elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-ml-5.15.*.rpm
grub2-set-default 0 && reboot
# 禁用通用调度器,NVMe 设为 none
echo none | tee /sys/block/nvme*/queue/scheduler
# 打开多队列与队列深度
for q in /sys/block/nvme*/queue/nr_requests; do echo 1024 > $q; done
# 关 readahead(随机负载)
for r in /sys/block/nvme*/queue/read_ahead_kb; do echo 0 > $r; done
2) NUMA/中断绑核
# CPU 拓扑
lscpu | egrep "NUMA node|CPU(s):"
# 让 NVMe 中断落在本地 NUMA 节点
irqbalance --oneshot --debug
# 或者用 set_irq_affinity 脚本按 pci 根绑定
3) 文件系统与挂载
mkfs.xfs -f -s size=4096 -n size=4096 /dev/nvme0n1
mount -o noatime,nodiratime,logbsize=256k,allocsize=1m /dev/nvme0n1 /data
4) 固件与 4K LBA
nvme id-ctrl /dev/nvme0 | egrep "tnvmcap|oncs|^mn"
nvme format /dev/nvme0n1 --lbaf=1 --data=1 # 确认 lbaf=1 对应 4KiB
现场踩坑与复盘(都是痛过才记住)
riser 降速到 Gen3
现象:LnkSta: Speed 8GT/s,顺序读卡在 ~3.1GB/s。
解决:换 Gen4 riser,主板 BIOS 把 PCIe Slot 固定 Gen4(有些默认 Auto 会降速)。
U.3 背板模式不当
现象:盘被识别成“经过某 HBA 抽象”的设备,延迟升高、IOPS 掉 10–20%。
解决:把背板 DIP 切到 NVMe-only,HBA 用 IT/直通固件 或干脆直连 CPU Root。
线材速率 / 方向不对
现象:个别位点不认盘、或只跑 Gen3。
解决:用 SlimSAS SFF-8654 4i 对 4x PCIe Gen4/5 规格线,注意单头/分叉方向;避免“便宜转接”。
VMD/RAID 误用
现象:开启 Intel VMD 或 HBA RAID1 后,随机写尾延上升明显。
解决:数据库日志、消息队列等低延迟路径,坚决直通;软件层面做镜像/纠删。
温控没跟上
现象:Gen5 在 18W 以上负载会到 70℃,出现间歇降频。
解决:把前风扇曲线抬两档;盘位加导风罩;U.2 托架贴导热垫到背板。
LBA/对齐
现象:512e + 默认分区对齐导致随机写放大。
解决:统一 4KiB LBA + 1MiB 对齐;XFS 自带更好的元数据布局,混合负载更稳。
如何选:一句话决策 + 详细建议
一句话决策
- 只要主板/背板支持,优先 Gen4;预算允许、写延迟敏感(交易撮合、日志/队列),上 Gen5。
- U.3 背板尽量 NVMe-only 直通;混插需求才用 tri-mode。
- 4KiB LBA + XFS,随机负载更稳,尾延更好控。
工作负载映射建议
| 负载 | 推荐接口/代际 | 代表盘 | 理由 |
|---|---|---|---|
| MySQL/OLTP,低延迟 | U.3/U.2 Gen5 | PM1743/CM7 | P99/P999 尾延明显好于 Gen4 |
| Kafka/日志、队列 | U.3/U.2 Gen4/5 | CM6/CM7 | 写稳态更好,掉电保护完善 |
| Elasticsearch/OLAP | Gen4 足够 | PM9A3/CM6 | 顺序读为主,性价比更高 |
| 对象存储元数据(Ceph MON/DB) | Gen4/5 小容量 | CM6/PM1743 | 小 IO 延迟更关键 |
| 冷数据/容量优先 | Gen3 也可 | P4510 | 预算友好,读多写少场景合适 |
成本提示:同容量下,Gen5 单价显著更高;除非你有明确尾延 KPI,不然 Gen4 是大多数业务的“甜点带”。
现场“可拷贝”安装与自检清单
# 1) 确认代际与通道
lspci -vv | egrep -A1 "Non-Volatile memory controller"
# 2) 盘健康、电容保护
smartctl -a /dev/nvme0n1 | egrep "Data Units|Media and Data Integrity Errors|Warning Composite Temperature"
# 3) 统一格式化 4K
nvme format /dev/nvme0n1 --lbaf=1 --force
# 4) XFS 创建与挂载
mkfs.xfs -f -s size=4096 -n size=4096 /dev/nvme0n1
mount -o noatime,nodiratime,logbsize=256k,allocsize=1m /dev/nvme0n1 /data
# 5) 快速 fio 冒烟(30 秒)
fio --name=smoke --filename=/dev/nvme0n1 --direct=1 --ioengine=io_uring \
--rw=randread --bs=4k --iodepth=32 --numjobs=4 --time_based=1 --runtime=30
# 6) 记录温度与功耗(供应商工具或 nvme smart)
nvme smart-log /dev/nvme0 | egrep "temperature|power_cycles|power_on_hours"
FAQ:常见纠结点
- U.2 还能买吗? 如果你的背板/服务器是上一代且只需要 NVMe,U.2 完全可用;注意线材与 riser 质量就好。
- 混插 SAS/SATA 值得吗? 除了迁移过渡期,不建议;混插常常带来模式误配与驱动栈复杂化。
- Gen5 值不值? 追求尾延的业务(撮合、风控、低延日志)值;以吞吐/成本为主的场景,Gen4 足矣。
收尾:日出前,风扇声终于不刺耳了
把 riser 和背板模式都校对完,最后一轮 fio 结束在 12.8GB/s 的曲线上。冷通道的风还是冷,但风扇不再把我吹得难受。
早上 6 点,客户的 MySQL 压上来,P999 仍旧压在 0.8ms 内,我把工单关掉时,机房外的天刚蒙蒙亮。
选 NVMe,别被名词吓住:把线路、背板、代际、LBA、文件系统这几样对上,剩下就是业务画像。
下次再来,我会直接带两套 Gen5 线材和 riser——不想再在 3 点半跟红字“8GT/s”对视了。
TL;DR 选型备忘卡(可收藏)
- 先看主板/背板是否支持 Gen4/Gen5,riser 与线材要同代际。
- U.3 背板尽量 NVMe-only,直通到 CPU Root;混插才用 tri-mode。
- 4KiB LBA + XFS,随机/混合负载延迟更稳。
- Gen4 是默认首选;尾延敏感负载上 Gen5。
- 上线前用 fio 冒烟 + LnkSta 校验,避开“降速到 Gen3”的隐形坑。