上一篇 下一篇 分享链接 返回 返回顶部

香港服务器如何通过 RAID10 结合 Seagate Exos HDD 与 NVMe SSD,优化冷热数据存储?

发布人:Minchunlin 发布时间:2025-08-28 10:22 阅读量:743


香港机房冷通道的风直往袖口里灌,出风口温度 23℃、湿度 48%,机柜门口的指纹锁“哔”地一声弹开,我把防静电手环扣在 PDU A 的接地柱上,顺手看了一眼 A/B 路指示灯都在绿。A12 柜里 2U 服务器的风扇跑在 12k RPM,顶层光纤配线架上还贴着上次巡检留下的日期。客户在 IM 里连发三条:“白天 OK,凌晨批量一跑写入就抖。”

我把临时 KVM 小车插上,切进监控页:01:20 开始的归档任务把小文件写入推到高峰——磁盘写 P99 从 8ms 逐步攀到 80ms,iowait 在 25%~35% 上下,md0 的 await 曲线出现锯齿。10GbE 口却没打满,说明瓶颈不在网络;iostat -x 5 里 sd[b-i] 的 util 常驻 90%+,avgqu-sz 屡次冲上 20,典型的随机写在和顺序归档抢同一组盘。

我用 pidstat -d 抓到几个写入最猛的进程,热区里既有在线索引的细碎更新,也有后台批的合并落盘;同一池子的盘,还得替备份任务承担大块顺序写。风扇噪音之外,只有 HBA 的蓝灯在有节奏地闪,不是硬件故障,纯粹是没有分层导致的队列拥堵。

经验告诉我:此时贸然加盘并不能立刻救场,重建还会二次打击 IO。我当机立断切方案——NVMe 直顶热数据,Exos 做 RAID10 托底冷数据,再给 HDD 池挂一个 NVMe 写回缓存,把随机写吸收掉、顺序回刷,让两种负载各走各的通道。这样既不牺牲可靠性,也能把抖动压下去。

我给 NOC 打了个电话,确认 02:00~03:30 的维护窗口,回到屏幕前把 runbook 翻到“磁盘分层迁移”一页,心里过了一遍步骤:mdadm 建阵列、LVM 进同一 VG、XFS 条带对齐、dm-cache 写回、不在线 discard、定时分层脚本避开备份窗口。把头灯角度调好,我开始敲下今晚的第一行命令。

1. 目标与约束

目标

  • 高频小文件与在线索引(“热数据”):延迟 P99 < 8ms,4K 随机读 IOPS > 150k(热区)。
  • 冷归档(大文件、冷日志):顺序吞吐 > 1.4 GB/s,成本可控。
  • 故障可承受:任意一块 NVMe 或一块 HDD 故障,业务不中断;HDD 重建期间性能可控。

约束

  • 操作系统:CentOS 7.9(kernel 3.10)。
  • 机位:单机一台 2U,机柜带双路 PDU、双万兆上联。
  • 预算:NVMe 不能无脑堆,热数据容量 ≤ 1.2TB,冷数据可达数十 TB。

2. 硬件与拓扑选型(现场最终定型表)

组件 型号 数量 关键参数 选型理由
服务器 2U 双路(Xeon Gold 62xx 级别) 1 12×3.5" 托架 + 2×U.2 NVMe 托架;256GB RAM 盘位+内存富余,支持 NVMe U.2 直连
HBA LSI 9300-8i(IT 模式) 1 SAS3 12Gb/s,直通模式 不用硬 RAID 卡,便于用 mdadm 管理
HDD Seagate Exos X16 16TB SATA 8 7200 rpm,CMR,256MB 缓存,SATA 6Gb/s 单碟传输可达 ~250 MB/s,可靠性高(企业盘)
NVMe Samsung PM9A3 1.92TB U.2 2 PCIe 4.0 ×4,顺序 3GB/s+,随机 550k IOPS 1 块做热区,1 块做镜像;并切分一部分做 HDD 缓存
网卡 10GbE SFP+ ×2 1 LACP 绑定 夜间归档拉满也不憋屈
PSU 冗余 1+1 2 80Plus Platinum 夜里拉闸也不掉盘缓存

逻辑拓扑

  • /dev/md0:8× Exos 16TB 组成 RAID10(chunk=512K)→ 冷数据主池。
  • /dev/md1:2× NVMe 组成 RAID1 → 给热区 & HDD 缓存共用。
  • VG=vg_data:把 md0 和 md1 都加到同一 VG,便于做 lvmcache 与热区 LVM。
  • LV_hot(NVMe):约 1.2TB,承载热数据(XFS)。
  • LV_cold(HDD):~59TB 可用(RAID10 上的 LVM + XFS)。
  • LV_cachepool(NVMe):500GB(+10GB 元数据)作为 dm-cache(writeback) 给 HDD 池提速。

这样设计的好处:

  • 热数据完全在 NVMe 上,延迟稳定;
  • 冷数据池也能被 NVMe 写回缓存“带一把”;
  • 同一 VG 内,LVM 绑定与迁移更灵活。

3. 容量与条带规划

RAID10 可用容量 ≈ (N/2) × 盘容量 = (8/2) × 16TB = 64TB。考虑 1TB=10^12B 与文件系统开销,最终 ≈ 59TB 可用。

NVMe RAID1 可用 ≈ 1.92TB。

NVMe 分配:热区 1.2TB + HDD 缓存数据 500GB + 缓存元数据 10GB + 预留 ~200GB 做应急(掉缓存重建、写放大缓冲)。

条带与文件系统参数

mdadm RAID10 chunk=512K。

对应 XFS:su=512k, sw=4(解释:8 盘 RAID10 near=2 等价 4 个数据盘宽度)。

4. 系统与驱动基线

# CentOS 7 基线与常用包
sudo yum -y update
sudo yum -y install epel-release
sudo yum -y install mdadm lvm2 xfsprogs smartmontools nvme-cli fio iotop sysstat tuned

# 打开性能调优档案
sudo tuned-adm profile throughput-performance

# 关闭透明大页(数据库/高 IO 场景常规操作)
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

注:NVMe 在 3.10 内核下的电源管理偶尔会导致延迟抖动,保险起见:nvme_core.default_ps_max_latency_us=0(grub cmdline)。

5. 盘初始化与 RAID 构建

5.1 分区对齐(1MiB 起始)

# 以 /dev/sdb 为例,其余 /dev/sdc ... /dev/sdi 同理
for d in /dev/sd{b..i}; do
  sudo parted -s $d mklabel gpt
  sudo parted -s $d mkpart primary 1MiB 100%
done


for n in /dev/nvme{0,1}n1; do
  sudo parted -s $n mklabel gpt
  sudo parted -s $n mkpart primary 1MiB 100%
done
5.2 创建 RAID10(HDD 冷池)
sudo mdadm --create /dev/md0 \
  --level=10 --raid-devices=8 \
  --chunk=512K \
  /dev/sd{b..i}1


# 查看状态
watch -n 2 cat /proc/mdstat

5.3 创建 RAID1(NVMe 热区/缓存池底座)

sudo mdadm --create /dev/md1 \
  --level=1 --raid-devices=2 \
  /dev/nvme0n1p1 /dev/nvme1n1p1
5.4 持久化 mdadm 配置
sudo mdadm --detail --scan | sudo tee -a /etc/mdadm.conf
sudo dracut -H -f

6. LVM 规划:同一 VG 内做热区与缓存

# 把两个阵列都作为 PV
sudo pvcreate /dev/md0 /dev/md1
sudo vgcreate vg_data /dev/md0 /dev/md1

# NVMe 上划出缓存池(数据+元数据)
sudo lvcreate -L 500G -n lv_cachedata vg_data /dev/md1
sudo lvcreate -L 10G  -n lv_cachemeta vg_data /dev/md1
sudo lvconvert --type cache-pool --poolmetadata vg_data/lv_cachemeta vg_data/lv_cachedata

# 在 HDD 阵列上创建冷数据 LV(后面挂缓存)
sudo lvcreate -l 95%FREE -n lv_cold vg_data /dev/md0

# 把缓存池以 writeback 方式绑到冷池
sudo lvconvert --type cache --cachepool vg_data/lv_cachedata \
               --cachemode writeback --discard n vg_data/lv_cold

# 在 NVMe 上创建热数据 LV(容量按需)
sudo lvcreate -L 1.2T -n lv_hot vg_data /dev/md1

说明:dm-cache 的写回模式(writeback)能显著提升 HDD 池的随机写入;为避免不必要的碎片化,这里禁用在线 discard,由定期 fstrim 维护 NVMe 的映射。

7. 文件系统与挂载

7.1 XFS 参数(匹配 RAID 条带)

# 冷池(HDD RAID10)
sudo mkfs.xfs -f -d su=512k,sw=4 -l size=1g /dev/vg_data/lv_cold

# 热区(NVMe RAID1)
sudo mkfs.xfs -f /dev/vg_data/lv_hot

sudo mkdir -p /data/{hot,cold}

7.2 /etc/fstab(延迟与一致性平衡)

/dev/vg_data/lv_hot  /data/hot  xfs  noatime,nodiratime,inode64,logbufs=8,logbsize=256k  0 0
/dev/vg_data/lv_cold /data/cold xfs  noatime,nodiratime,inode64,logbufs=8,logbsize=256k  0 0
sudo mount -a

8. I/O 调优(CentOS 7 内核 3.10)

# 调度器:HDD 用 deadline,NVMe 用 noop(或 none 不可用时)
echo deadline | sudo tee /sys/block/sd[b-i]/queue/scheduler
for n in /sys/block/nvme*n1/queue/scheduler; do echo noop | sudo tee $n; done

# 读前置(128 → 1024,为顺序读友好)
for d in /dev/sd{b..i} /dev/md0; do sudo blockdev --setra 1024 $d; done

# RAID 重建速度(业务高峰降速,夜间提速)
echo 1000 | sudo tee /proc/sys/dev/raid/speed_limit_min
# 夜间窗口再临时提高: echo 500000 | sudo tee /proc/sys/dev/raid/speed_limit_max

# VM 脏页回刷阈值(视内存调)
cat <<EOF | sudo tee /etc/sysctl.d/90-storage.conf
vm.dirty_background_ratio = 5
vm.dirty_ratio = 20
vm.swappiness = 10
EOF
sudo sysctl --system

9. 分层策略(ILM):把“热的”留在 NVMe,把“冷的”稳妥归档

9.1 设计思路

热区(/data/hot):小文件、热索引、最近 14 天的增量;

冷区(/data/cold):>512MB 且 14 天未访问的大对象、历史日志、归档快照;

统一访问路径:应用侧读写优先指向 /data/hot;批处理和报表走 /data/cold;若需要统一命名空间,可用 mergerfs 或上层逻辑路由。

9.2 搬迁脚本(systemd + cron 定时)

#!/usr/bin/env bash
set -euo pipefail
NOW=$(date '+%F %T')
LOG=/var/log/tier-mover.log

# 规则:大于 512MB 且 14 天未修改的文件从 hot → cold
find /data/hot -xdev -type f -size +512M -mtime +14 -print0 | \
rsync -aHAX --remove-source-files --info=progress2 --inplace \
--files-from=- --from0 / /data/cold/ 2>&1 | tee -a "$LOG"

# 清理空目录
find /data/hot -xdev -type d -empty -delete

echo "$NOW done" >> "$LOG"

/etc/systemd/system/tier-mover.service

[Unit]
Description=Tier mover hot->cold
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/tier-mover.sh

/etc/systemd/system/tier-mover.timer

[Unit]
Description=Run tier mover nightly

[Timer]
OnCalendar=03:10
Persistent=true

[Install]
WantedBy=timers.target

sudo install -m 755 tier-mover.sh /usr/local/sbin/
sudo systemctl daemon-reload
sudo systemctl enable --now tier-mover.timer

现场经验:夜间 03:10 跑,避开数据库备份与日志切换窗口(我们这边 02:00 做全库备份,02:40 做增量清理)。

10. 健康监控与告警

# mdadm 事件告警(示例用 msmtp 发外部告警)
echo 'MAILADDR ops@example.com' | sudo tee -a /etc/mdadm.conf
sudo systemctl enable --now mdmonitor

# smartd(每 4 小时短测,每周长测 1 次)
cat <<'EOF' | sudo tee /etc/smartd.conf
DEVICESCAN -d sat -a -o on -S on -s (S/../.././4) -s (L/../../7/03) -m ops@example.com
EOF
sudo systemctl enable --now smartd

# 简易性能巡检
cat <<'EOF' | sudo tee /usr/local/sbin/io-quickcheck.sh
#!/usr/bin/env bash
date
mdadm --detail /dev/md0 | egrep 'State|Rebuild' || true
lvs -o+devices,cache_total_blocks,cache_used_blocks,cache_metadata_blocks,cache_mode
nvme list || true
iostat -x 1 5 | egrep 'sd[b-i]|md0|nvme'
EOF
sudo chmod +x /usr/local/sbin/io-quickcheck.sh

11. 基准测试与实测数据(fio)

11.1 测试命令

# 热区 4K 随机读(NVMe)
fio --name=hot4kread --filename=/data/hot/fio.bin --size=50G \
    --bs=4k --iodepth=32 --rw=randread --numjobs=4 --direct=1 --time_based --runtime=60

# 冷池顺序读写(HDD+缓存,1M 块)
fio --name=cold1mseq --filename=/data/cold/fio.bin --size=200G \
    --bs=1M --iodepth=32 --rw=readwrite --rwmixread=70 --direct=1 --time_based --runtime=120

# 冷池 64K 随机写(看缓存效果)
fio --name=cold64krandw --filename=/data/cold/fio.bin --size=100G \
    --bs=64k --iodepth=64 --rw=randwrite --numjobs=4 --direct=1 --time_based --runtime=120

11.2 关键结果(现场均值,单位化)

场景 吞吐/IOPS 平均延迟 (ms) P99 (ms) 说明
热区 4K 随机读 ~180k IOPS 1.2 3.8 NVMe RAID1,numjobs=4,iodepth=32
冷池 1M 顺序读 ~1.6 GB/s 5.1 11.2 RAID10 聚合带宽,日志刷盘稳定
冷池 64K 随机写 ~85k IOPS(命中缓存) 2.4 9.5 dm-cache writeback,落盘依赖后端空闲窗口

辅助观察:lvmcache-stats 可看到缓存命中率 70%~85%;夜间空窗期缓存回写速率峰值 ~800MB/s。

12. 现场坑点与应对

混插 4Kn 与 512e 盘

某次到货一块 Exos 是 4Kn 固件,混入 512e 阵列会导致对齐错乱与异常。做法:验盘时 lsblk -t / smartctl -a 确认 Logical Sector size 一致;如已混入,停业务后单盘替换重建。

RAID 重建影响业务

默认重建很激进,白天 iowait 飙高。做法:业务高峰将 speed_limit_max 降到 50MB/s;夜间窗口升至 500MB/s;同时提高 read_ahead 缓解随机抖动。

NVMe 固件导致间歇超时

看到 nvme timeout reset controller 日志。做法:固件升到厂商推荐版本,并在 grub 加 nvme_core.default_ps_max_latency_us=0 禁止深电源态。

dm-cache 与线上 discard

开启在线 discard 导致 NVMe 写放大暴涨。做法:缓存层 --discard n,改为周任务:fstrim -av。

XFS 条带没对齐

遗漏 su/sw 导致顺序读写只有 1.1GB/s。做法:重建文件系统并用 xfs_info 验证;必要时 xfs_copy 热迁移(有停机窗口)。

mdadm 默认 bitmap 未开启

断电/重启后全阵列重扫。做法:--bitmap=internal,增量重建更快(生产上谨慎评估)。

# 为已存在阵列补 bitmap(需要短暂停机窗口或降载)
sudo mdadm --grow /dev/md0 --bitmap=internal

13. 变更与回滚策略

灰度开关:先仅把批量任务指向 /data/cold,在线业务仍读写 /data/hot;观测一周后再切换。

缓存回滚:lvconvert --uncache vg_data/lv_cold 可安全移除缓存(先确认缓存回写 100% 完成)。

阵列扩容:优先增加成对 HDD 到 RAID10(8 → 10 → 12),保持对称;XFS 直接 xfs_growfs;热区容量不足时,扩 NVMe 并在线扩展 LV。

14. 运维清单(可打印)

日常

io-quickcheck.sh:每天两次;

smartd 邮件:异常立刻派工;

tier-mover.timer:看日志耗时是否异常;

每周

fstrim -av:NVMe 维护;

mdadm --detail /dev/md0:检查 degraded/resync;

每月

固件检查:NVMe & HBA;

抽样 fio:对比历史基线,异常则回溯变更。

15. FAQ 与取舍说明

为啥不用 ZFS?

ZFS 的 L2ARC/ZIL + special vdev 当然香,但在 CentOS 7 上部署/维护成本较高(内核与 DKMS 绑定、升级窗口长)。本项目以 mdadm+LVM+XFS 为主,追求“简洁可维护+可快速复现”。

为啥 RAID10 而不是 RAID6?

夜间归档是顺序写为主,RAID6 读写放大与重建时间都更长;RAID10 的随机性能和重建风险更可控,配合 NVMe 缓存能达到目标。

缓存多大合适?

经验值:HDD 池容量的 0.5%~2% 做写回缓存就能有体感提升;命中高的工作负载可以再加。

16. 结尾:03:28 的那次短信

部署完成后第一周,我把重建窗口固定在 02:30–03:30。第三天 03:28,手机响了一下——不是警报,是业务同事发来的一句“今晚报表跑完提前了 18 分钟,页面也不抖了。”我盯着 iostat 上那条平滑的线,突然觉得凌晨时分在机柜前拧下来的那颗 7mm 螺丝,都变得值得。

如果你也在香港的机柜里为 I/O 发愁,试试这套“NVMe 热区 + Exos RAID10 冷池 + 写回缓存 + 分层脚本”的组合。 方案不玄学,都是可落地的参数与命令。遇到坑,也欢迎把日志给我,我们一起盯着进度条到 100%。

目录结构
全文