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

香港服务器运行Debian 10时,如何配置XFS文件系统和RAID阵列,提升大数据应用的存储吞吐量?

发布人:Minchunlin 发布时间:2025-08-27 09:35 阅读量:759


凌晨 02:10,我捧着半杯凉掉的美式,站在香港葵涌机房第 3 排第 6 柜前。客户的 ClickHouse 集群白天刚顶了一波高峰,单节点存储吞吐被打爆,业务侧拼命做分片,可单机 I/O 还是瓶颈。这篇文章,是那一夜我在香港机房里,从盘位摸到文件系统的全过程——踩过的坑、做过的测试、最后稳定落地的参数,一条龙交给你。新手能照做,老手也能抠细节。

目标与场景

目标:在 Debian 10(Buster)上,为大数据/分析型负载(ClickHouse / Kafka / HDFS DataNode)构建高吞吐、可恢复的本地存储卷。

方案:基于 mdadm 实现 RAID(以 RAID10 为主),文件系统选 XFS,结合条带(stripe)与挂载参数调优。

负载特征:顺序读写为主(批处理、合并、后台压缩),夹杂中等随机写(写放大和小文件元数据压力)。

实机参数与环境(现场记录)

项目 配置
机型 2U 通用服务器
CPU 2 × Intel Xeon Silver(共 24 物理核)
内存 256 GB DDR4
HBA LSI 9300-8i(IT 模式)
数据盘 8 × 4TB 7200RPM 企业级 SATA(带 RV 传感器)
系统盘 2 × 960GB SATA SSD(做 RAID1 给 OS)
额外 NVMe(可选) 1 × 1.6TB NVMe(预留 XFS 外置日志/冷热分层)
OS Debian 10 (Buster) 4.19 内核
关键包 mdadmxfsprogssmartmontoolsfio

落地策略:

  • ClickHouse 节点:本地卷需要高顺序吞吐与较快重建 → RAID10(near layout)+ XFS。
  • Kafka 节点:也常用 RAID10;若追求极致性能且上层多副本,有时会用 JBOD/RAID0(此文以 RAID10 为主线)。
  • HDFS DataNode:若上层三副本且强依赖分布式冗余,JBOD 亦可,但本文围绕标题选 RAID10。

RAID 选择与条带计算

RAID 方案取舍(实话实说)

方案 顺序吞吐 随机读写 重建风险 容量利用 适用
RAID0 极高 一般 极高(坏一块全毁) 100% 上层多副本、临时盘
RAID5/6 一般 重建时间长,穿越读风险 75%/66% 容量敏感但可容忍重建风险
RAID10 较低(重建快) 50% 分析/日志/OLAP 节点首选

本次落地:8 盘做 RAID10,--layout=n2(near),--chunk=512K。

  • 可并发数据盘数 sw = N / copies = 8/2 = 4
  • XFS stripe 建议:su = 512K,sw = 4(下面 mkfs 会用)。

上线前健康检查与对齐

磁盘健康(别嫌麻烦,救命用)

apt-get update && apt-get install -y smartmontools
for d in /dev/sd[b-i]; do
  smartctl -a $d | egrep "Model|Serial|Power_On_Hours|Reallocated|Pending"
done

有不健康的盘,先换;别带病上线。

分区对齐(1MiB 对齐,避免写放大)

apt-get install -y parted
for d in /dev/sd[b-i]; do
  parted -s $d mklabel gpt
  parted -s -a optimal $d mkpart data 1MiB 100%
done

用 mdadm 创建 RAID10

apt-get install -y mdadm

# 创建 RAID10(near=2,条带 512K)
mdadm --create /dev/md0 \
  --level=10 \
  --raid-devices=8 \
  --chunk=512 \
  --layout=n2 \
  /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1 /dev/sdf1 /dev/sdg1 /dev/sdh1 /dev/sdi1

# 查看进度
watch -n 3 cat /proc/mdstat

经验:创建时就把 chunk 定好,后续改代价大。条带越大,顺序吞吐越好(但小 I/O 可能浪费)。

阵列持久化(否则重启可能丢阵列名):

mdadm --detail --scan | tee -a /etc/mdadm/mdadm.conf
update-initramfs -u

在 RAID 上创建 XFS(带几项关键参数)

参数思路(给老司机看)

  • -d su=512k,sw=4:和上面 RAID10 条带匹配,减少跨带写放大。
  • -l size=1024m:放大日志区,缓解高并发写入下的元数据堵塞。
  • -n ftype=1:目录项携带文件类型(容器/OverlayFS 友好)。
  • -m reflink=0:关闭 CoW(大顺序写为主的 OLAP/Kafka 通常不需要 CoW;如需快照/去重再考虑开)。
apt-get install -y xfsprogs

mkfs.xfs -f \
  -d su=512k,sw=4 \
  -l size=1024m \
  -n ftype=1 \
  -m reflink=0 \
  /dev/md0

验证 stripe 信息(注意单位:sunit/swidth 是以 4K 块为单位的):

xfs_info /dev/md0
# 期望看到:sunit=128 (512K/4K),swidth=512 (128*4),与上面 su/sw 对应

挂载与 fstab(稳字当头)

挂载选项(顺序吞吐优先、安全第一):

  • noatime:减少 atime 写入。
  • inode64:海量 inode 时表现更好。
  • logbufs=8,logbsize=256k:加大日志缓冲,提高并发。
  • 不要随便 nobarrier(断电风险)。有 UPS + 带电容/BBU 的控制器再评估。
  • SSD 才考虑 discard(或用周期性 fstrim)。
mkdir -p /data
echo "/dev/md0 /data xfs defaults,noatime,inode64,logbufs=8,logbsize=256k 0 0" >> /etc/fstab
mount -a && df -h /data

可选:把 NVMe 做 外置日志(元数据压力极大时有效)

# 假设 /dev/nvme0n1p1 预留 10-20G 做 logdev
mkfs.xfs -f -d su=512k,sw=4 -l logdev=/dev/nvme0n1p1,size=2048m -n ftype=1 -m reflink=0 /dev/md0
mount -o logdev=/dev/nvme0n1p1 /dev/md0 /data

系统级调优(少量参数,收益可观)

读提前(readahead):顺序读明显增益

# 底层物理盘与阵列都设大点,例如 64MB
blockdev --setra 131072 /dev/md0
for d in /dev/sd[b-i]; do blockdev --setra 131072 $d; done

I/O 调度器

  • SATA/SAS:mq-deadline 一般靠谱;
  • NVMe:默认 none,保持即可。

查看/设置(示例):

cat /sys/block/md0/queue/scheduler
echo mq-deadline > /sys/block/md0/queue/scheduler

脏页回刷(降低写峰值卡顿)

cat <<EOF >> /etc/sysctl.d/99-io-tuning.conf
vm.dirty_background_ratio=5
vm.dirty_ratio=10
EOF
sysctl --system

md 重建速度(生产窗口谨慎)

echo 50000 > /proc/sys/dev/raid/speed_limit_max   # 单位 KB/s
echo 20000 > /proc/sys/dev/raid/speed_limit_min

基准测试(fio 模板与指标)

测试目录:/data;务必避开业务高峰,确保 direct=1 直写。

顺序写(1MiB,4 并发,100G)

fio -name=seqwrite -directory=/data -numjobs=4 -ioengine=libaio \
  -rw=write -bs=1M -size=100G -iodepth=32 -direct=1 -group_reporting

顺序读

fio -name=seqread -directory=/data -numjobs=4 -ioengine=libaio \
  -rw=read -bs=1M -size=100G -iodepth=32 -direct=1 -group_reporting

混合读写(70/30)

fio -name=mix -directory=/data -numjobs=8 -ioengine=libaio \
  -rw=randrw -rwmixread=70 -bs=128k -size=50G -iodepth=64 -direct=1 -group_reporting

现场实测(代表值,仅供参考)

场景 参数 吞吐 / IOPS(平均) 延迟(平均)
顺序写 1M × 4 并发 0.85–1.0 GB/s 8–12 ms
顺序读 1M × 4 并发 1.3–1.6 GB/s 5–9 ms
混合 70/30 128k × 8 并发 450–650 MB/s / 3–6k IOPS 6–15 ms

注:chunk=1M 也测过,顺序读略高、混合随机略降;考虑业务占比,最终定 512K。

XFS 细节再抠一点(给发烧友)

AG(Allocation Group):并行元数据与并发分配更强。大盘可适当增加 agcount,例如 16:

mkfs.xfs -f -d su=512k,sw=4,agcount=16 -l size=1024m -n ftype=1 -m reflink=0 /dev/md0

预分配:大文件写入前 fallocate,减少碎片:

fallocate -l 200G /data/ch_data_part.bin

在线扩容:新增盘 → 扩 RAID → xfs_growfs /data(XFS 不能收缩,先规划再上)。

应用层落地建议

ClickHouse

storage_configuration 中把大表落在 /data,后台合并高峰期避免和备份/TTL 清理撞车。

max_bytes_before_external_group_by/sort 根据内存调,降低落盘风暴。

周期性 fstrim(如果底层含 SSD/NVMe 分层)。

Kafka

log.dirs=/data/kafka-logs;多个卷时每盘一个目录,避免单卷热区。

num.recovery.threads.per.data.dir 与 CPU/盘数匹配;flush.messages 不要过激。

log.segment.bytes 合理增大,减少 segment 切换的元数据开销。

HDFS DataNode

RAID10 与 JBOD 二选一。若已选 RAID10,DataNode 配置中把卷识别清楚;namenode 端副本策略按机架/节点分散,规避同阵列双副本。

我踩过的坑(以及我怎么解)

创建完阵列重启进了 initramfs

原因:/etc/mdadm/mdadm.conf 没写入阵列信息。

解决:mdadm --detail --scan >> /etc/mdadm/mdadm.conf && update-initramfs -u,再重启。

顺序写吞吐忽上忽下

排查:iostat -x 1 看到个别盘 await 飙高,smartctl 显示写错误重试。

处理:先下线该盘 mdadm /dev/md0 -f /dev/sdx1,更换热备补回;恢复后吞吐稳定。

xfs 日志打满,应用写阻塞

现象:dmesg 里 XFS: busy 相关提示。

处理:-l size=1024m 放大日志,并用 logbufs=8,logbsize=256k;高峰错峰合并/压缩任务。

对齐没做好,fio 秒数奇长

经验:务必用 parted -a optimal,并核对 xfs_info 的 sunit/swidth 与 RAID 条带一致。

重建时业务抖动明显

做法:在业务低谷提重建限速,在高峰调低:

echo 100000 > /proc/sys/dev/raid/speed_limit_max
# 高峰期再降到 20000-50000

误开 nobarrier 导致断电后元数据损伤

反思:除非有可靠的写缓存保护(BBU/超容电容)+ UPS,不要开。

一键回看:关键命令清单

# 健康检查
apt-get install -y smartmontools mdadm xfsprogs fio parted
for d in /dev/sd[b-i]; do smartctl -a $d; done

# 分区对齐
for d in /dev/sd[b-i]; do
  parted -s $d mklabel gpt
  parted -s -a optimal $d mkpart data 1MiB 100%
done

# 创建 RAID10
mdadm --create /dev/md0 --level=10 --raid-devices=8 --chunk=512 --layout=n2 /dev/sd[b-i]1
mdadm --detail --scan | tee -a /etc/mdadm/mdadm.conf
update-initramfs -u

# XFS(条带匹配 + 大日志)
mkfs.xfs -f -d su=512k,sw=4 -l size=1024m -n ftype=1 -m reflink=0 /dev/md0
mkdir -p /data
echo "/dev/md0 /data xfs defaults,noatime,inode64,logbufs=8,logbsize=256k 0 0" >> /etc/fstab
mount -a

# 调优
blockdev --setra 131072 /dev/md0; for d in /dev/sd[b-i]; do blockdev --setra 131072 $d; done
echo mq-deadline > /sys/block/md0/queue/scheduler
sysctl -w vm.dirty_background_ratio=5 vm.dirty_ratio=10

# 验证
xfs_info /dev/md0
fio ... # 如上模板

结果回顾(对比表)

设置 顺序读 顺序写 备注
RAID10 + XFS 默认 1.1–1.3 GB/s 0.7–0.8 GB/s 无条带匹配
RAID10(chunk=512K)+ XFS(su=512K, sw=4) 1.3–1.6 GB/s 0.85–1.0 GB/s 主要收益来自条带对齐
+ readahead 64MB、logbufs 调优 1.4–1.6+ GB/s 0.9–1.0 GB/s 抖动更小

从机房出来,风还在吹

早上 05:40,机房外的海风顺着货柜码头吹过来。我重新看了一眼监控面板,吞吐在高位稳得像钉在墙上的水准仪。客户白天再冲一波,我们的 I/O 也不再虚。存储这活儿,终究是工程:从盘到阵列,从条带到文件系统,从参数到上线窗口,每一步都能决定最终的业务体验。

如果你也在香港的某个机柜前纠结 RAID 和 XFS 的参数,希望这篇实战给你一点确定性:

  • 把条带算明白,把日志配大,把回刷和读提前调顺,再用你自己的数据去测。
  • 别怕深夜,那是运维最清醒的时候。

附:通用故障速查

  1. 阵列掉盘:mdadm --detail /dev/md0 + dmesg → 标记失败盘并更换 -f / -r。
  2. XFS 异常关机后检查:xfs_repair -n /dev/md0(只读检查),有需要再去掉 -n。
  3. 空间不足又想扩容:先物理加盘 → 扩 RAID → xfs_growfs /data。
  4. 长期维护:mdadm --monitor --scan --daemonise --syslog,配合报警系统。
  5. 有问题就按这套落地跑一遍,你会发现:不是玄学,是细节。
目录结构
全文