如何在香港服务器的 Debian 系统中,把 Ceph 分布式存储“拧”到能扛 AI 训练数据的高速并发访问

夜里 2:40,我站在香港机房冷风口正对的那一排柜前面,第 3 次重跑的多机多卡训练又在第一个小时炸了:dataloader timeout。GPU 没问题,NVLink 也没掉,问题瞄准在 I/O——64 块 GPU 同时抽样读取 100+ TB 的训练样本,我们那套“单机 NVMe + NFS 拼凑”的临时方案已经彻底扛不住了。
我当场决定改:把存储全量上 Ceph,用 CephFS 给训练读数据、用 RGW(S3) 撑 ingest 通道、用 RBD 做中间态与 checkpoint。系统是我们常用的 Debian(香港机房的托管商镜像齐全),这活儿得趁业务低谷窗口一把梭。
下面是我在香港机房用 Debian + Ceph 搭起来、并实战扳平训练 I/O 瓶颈的全流程,既讲怎么做,也讲踩了哪些坑、怎么填。写得细,目的是让新手也能照着抄,高阶同学也能直接拿走细节和参数落地。
1)目标与场景
- 数据规模:原始样本 ~120 TB,后续每月增量 10–20 TB
- 客户端并发:8 台训练节点 × 每台 8 GPU(共 64 workers),每个 worker 小批量随机读取 1–8 MB 对象/文件
- 吞吐目标:单训练节点 1.2–1.6 GB/s 聚合读;全集群聚合 8–12 GB/s;p95 读延迟 ≤ 8 ms(4 MB 顺序块)
访问模式:
- 训练集:读多写少(热读 + 少量元数据操作)→ CephFS
- 数据入湖(预处理/清洗/增量导入):对象追加与并发写 → RGW (S3)
- checkpoint/中间态:本地文件系统语义 + 顺序写 → RBD + XFS/ext4
2)硬件与网络拓扑(香港机房实配)
2.1 节点配置
| 角色 | 数量 | 机型/CPU | 内存 | 系统盘 | 数据盘(OSD) | DB/WAL | 网卡 |
|---|---|---|---|---|---|---|---|
| MON/MGR | 3 | Xeon Silver 4314 | 64 GB | 2×480G SATA | — | — | 2×25GbE |
| MDS | 2(active-standby,可扩至2 active) | Xeon Gold 6338N | 128 GB | 2×480G | — | — | 2×25GbE |
| RGW | 2 | Xeon Silver 4314 | 64 GB | 2×480G | — | — | 2×25GbE |
| OSD | 8 | AMD EPYC 7543P | 256 GB | 2×480G | 12×18TB HDD (SAS 7200) | 2×1.92TB NVMe(PM9A3) | 2×100GbE |
| 训练节点 | 8 | AMD EPYC + 8×A100 80G | 512 GB | 2×960G NVMe | — | — | 2×100GbE |
设计要点:HDD 做容量与吞吐主体,NVMe 只做 Bluestore DB/WAL(每 NVMe 绑 5–6 块 HDD);OSD 机器上网卡走 双 100GbE,Public/Cluster 两网分离。
2.2 网络设计
- Public 网络(客户端/Mon/Mgr/MDS/RGW):10.0.10.0/24(VLAN 110,MTU 9000)
- Cluster 网络(OSD 复制/恢复):10.0.20.0/24(VLAN 120,MTU 9000)
- 交换机:TOR 100G,LACP 到汇聚;端口关闭 storm-control 对存储 VLAN 的限速;强制开启 flow-control
- 时钟:Chrony 对齐机房 PTP/NTP,禁止时间大幅漂移(Mon 最怕 clock skew)
3)操作系统与基础调优(以 Debian 12 bookworm 为例)
# 基础
apt update && apt -y install chrony lvm2 nvme-cli jq htop ethtool numactl
# 关闭交换(Ceph OSD 不喜欢频繁 swap)
swapoff -a
sed -i 's/^\(.*swap.*\)$/# \1/g' /etc/fstab
# CPU 电源策略(降低尾延迟)
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
# 磁盘 I/O 调度(HDD 推荐 mq-deadline;NVMe 一般 none)
for d in /sys/block/sd*/queue/scheduler; do echo mq-deadline > $d; done
for d in /sys/block/nvme*/queue/scheduler; do echo none > $d; done
# 网卡调优(示例,按实际 NIC 名称)
ip link set dev eth0 mtu 9000
ip link set dev eth1 mtu 9000
ethtool -G eth0 rx 4096 tx 4096
ethtool -K eth0 tso on gso on gro on rxvlan on txvlan on
# 内核参数(网络缓冲/内存回收)
cat >> /etc/sysctl.d/99-ceph.conf <<EOF
net.core.rmem_max=268435456
net.core.wmem_max=268435456
net.ipv4.tcp_rmem=4096 87380 268435456
net.ipv4.tcp_wmem=4096 65536 268435456
vm.swappiness=1
vm.vfs_cache_pressure=50
EOF
sysctl --system
4)Ceph 版本与角色规划
部署方式:cephadm(容器化,易运维,Debian 上体验稳定)
组件角色:
- MON ×3、MGR ×2
- MDS ×2(起步 1 active + 1 standby;大目录并发时开到 2 active)
- RGW ×2(同域冗余,前面挂 LVS/NGINX)
- OSD:HDD ×96(8 台 × 每台 12 盘) + NVMe ×16(DB/WAL)
池设计:
- cephfs.ai.data:副本 3(热数据),pg_autoscale=on
- cephfs.ai.meta:副本 3
- s3.ai.ec(冷数据备存,可选):纠删码 8+2
- rbd.ckpt:副本 3(训练 checkpoint)
PG 预估:起步按 100 PG/OSD × 96 OSD / 副本数 ≈ 3200 PG/热数据池。开启 autoscaler 后让它逐步收敛,避免一次性打爆 MON/MGR 内存。
5)部署步骤(cephadm)
5.1 引导集群(在任一控制节点)
apt -y install cephadm
# Bootstrap:指定 mon IP、集群与公共网络
cephadm bootstrap \
--mon-ip 10.0.10.11 \
--cluster-network 10.0.20.0/24 \
--initial-dashboard-user admin \
--initial-dashboard-password 'S3cure#Pass'
5.2 加入主机并打标签
# 依次把各主机加进编排器
cephadm shell -- \
ceph orch host add ceph-mon01 10.0.10.11
cephadm shell -- \
ceph orch host add ceph-mon02 10.0.10.12
cephadm shell -- \
ceph orch host add ceph-mon03 10.0.10.13
# OSD 宿主
for i in {01..08}; do
cephadm shell -- ceph orch host add ceph-osd$i 10.0.10.$((20+i))
cephadm shell -- ceph orch host label add ceph-osd$i osd
done
# MDS / RGW 宿主
cephadm shell -- ceph orch host add ceph-mds01 10.0.10.40
cephadm shell -- ceph orch host add ceph-mds02 10.0.10.41
cephadm shell -- ceph orch host label add ceph-mds01 mds
cephadm shell -- ceph orch host label add ceph-mds02 mds
cephadm shell -- ceph orch host add ceph-rgw01 10.0.10.50
cephadm shell -- ceph orch host add ceph-rgw02 10.0.10.51
cephadm shell -- ceph orch host label add ceph-rgw01 rgw
cephadm shell -- ceph orch host label add ceph-rgw02 rgw
5.3 布署 MON/MGR/MDS/RGW
cephadm shell -- ceph orch apply mon 3
cephadm shell -- ceph orch apply mgr 2
# MDS:先 1 active + 1 standby,后续可扩
cephadm shell -- ceph orch apply mds cephfs-ai --placement="count:2 label:mds"
# RGW:简单起步,后续再做 realm/zone 规划
cephadm shell -- ceph orch apply rgw rgw.ai --placement="count:2 label:rgw" --port 8080
5.4 OSD(DriveGroup:HDD+NVMe DB/WAL)
cat > /tmp/osd-dg.yaml <<'YAML'
service_type: osd
service_id: hdd-osd
placement:
label: "osd"
data_devices:
rotational: 1
size: ">= 14TB"
db_devices:
rotational: 0
size: ">= 1000GB"
limit: 6 # 每块 NVMe 绑 6 块 HDD 作为 DB
wal_devices:
rotational: 0
size: ">= 100GB"
YAML
cephadm shell -- ceph orch apply -i /tmp/osd-dg.yaml
Bluestore 建议:osd_memory_target=8G(按内存酌情提高至 10–12G),bluestore_cache_autotune=true(默认开启),HDD 的 bluestore_min_alloc_size_hdd=64K。
6)创建池与 CephFS / RGW / RBD
# 热数据池 + 元数据池(PG 数交给 autoscaler)
ceph osd pool create cephfs.ai.data 0
ceph osd pool create cephfs.ai.meta 0
ceph osd pool application enable cephfs.ai.data cephfs
ceph osd pool application enable cephfs.ai.meta cephfs
ceph osd pool set cephfs.ai.data pg_autoscale_mode on
ceph osd pool set cephfs.ai.meta pg_autoscale_mode on
# 创建 CephFS 并允许多活 MDS
ceph fs new cephfs-ai cephfs.ai.meta cephfs.ai.data
ceph fs set cephfs-ai max_mds 2
ceph fs set cephfs-ai allow_multimds true
ceph fs set cephfs-ai standby_count_wanted 1
(可选)纠删码对象池 + RGW:
# 纠删码配置 8+2,适合冷数据归档,训练热点仍建议副本池
ceph osd erasure-code-profile set ec82 k=8 m=2 crush-failure-domain=host
ceph osd pool create s3.ai.ec 0 0 erasure ec82
ceph osd pool application enable s3.ai.ec rgw
# RGW 基础用户
radosgw-admin user create --uid=trainer --display-name="trainer" \
--access-key=<AK> --secret-key=<SK>
RBD(给 checkpoint):
ceph osd pool create rbd.ckpt 0
rbd pool init rbd.ckpt
rbd create --size 102400 --image-feature layering rbd.ckpt/ckpt-01 # 100GB
7)客户端挂载与对接训练框架
7.1 训练节点挂载 CephFS(推荐内核客户端)
创建应用用户与密钥:
ceph auth get-or-create client.ai \
mon 'allow r' \
mds 'allow rw path=/ai' \
osd 'allow rw pool=cephfs.ai.data' \
> /etc/ceph/ceph.client.ai.keyring
# 只取 key 放 secretfile
ceph auth get-key client.ai > /etc/ceph/ai.secret
chmod 600 /etc/ceph/ai.secret
挂载(3 个 mon 地址):
mkdir -p /mnt/cephfs
mount -t ceph 10.0.10.11,10.0.10.12,10.0.10.13:/ /mnt/cephfs \
-o name=ai,secretfile=/etc/ceph/ai.secret,fs=cephfs-ai,_netdev,noatime
# /etc/fstab(便于开机挂载)
echo "10.0.10.11,10.0.10.12,10.0.10.13:/ /mnt/cephfs ceph name=ai,secretfile=/etc/ceph/ai.secret,fs=cephfs-ai,_netdev,noatime 0 2" >> /etc/fstab
布局与条带:在 CephFS 中对“超大文件/分片包”设置条带能提升多客户端并发吞吐。示例(把大 tar shard 条带为 4MB × 8 条):
setfattr -n ceph.file.layout.stripe_unit -v 4194304 file.tar
setfattr -n ceph.file.layout.stripe_count -v 8 file.tar
7.2 S3(RGW)导入数据
# s5cmd 高并发导入(训练前准备)
s5cmd --endpoint-url http://rgw.vip.ai:8080 \
--access_key <AK> --secret_key <SK> \
cp -n -p ./dataset_shards/*.tar s3://ai-ds/
7.3 PyTorch 侧读取最佳实践
- 强烈建议:将海量小文件打包成 tar 分片(WebDataset)或 LMDB,减少元数据风暴。
- DataLoader 设置:num_workers = 4~8(视 CPU)、prefetch_factor=2~4、pin_memory=True。
分布式采样避免“热点分片”。
例如 WebDataset:
import torch, webdataset as wds
def make_loader(urls, batch_size):
dataset = (
wds.WebDataset(urls).shuffle(1000)
.decode("pil")
.to_tuple("jpg;png", "json")
.map_tuple(lambda x: x.convert("RGB"), lambda y: y)
)
return torch.utils.data.DataLoader(
dataset.batched(batch_size),
num_workers=8, prefetch_factor=3, pin_memory=True
)
urls = "pipe:cat /mnt/cephfs/ai/shards/shard-{000000..000999}.tar"
loader = make_loader(urls, batch_size=64)
7.4 Checkpoint 放 RBD
# 训练节点:map RBD
rbd map rbd.ckpt/ckpt-01
mkfs.xfs /dev/rbd/rbd/ckpt-01
mkdir -p /mnt/ckpt && mount /dev/rbd/rbd/ckpt-01 /mnt/ckpt
8)性能与可靠性调优
8.1 OSD / 集群侧
# 合理的 OSD 内存目标(HDD 多、内存足时可 8–12G)
ceph config set osd osd_memory_target 8589934592
# 恢复与重平衡限速(训练高峰期降噪音,低峰放开)
ceph config set osd osd_max_backfills 2
ceph config set osd osd_recovery_max_active 2
ceph config set osd osd_recovery_sleep 0.1
# 定时窗口内暂停深度校验(scrub)
ceph osd set noscrub
ceph osd set nodeep-scrub
# 低峰再开:ceph osd unset noscrub; ceph osd unset nodeep-scrub
8.2 MDS / CephFS
# 大目录并发:多活 MDS 与缓存
ceph fs set cephfs-ai max_mds 2
ceph config set mds mds_cache_memory_limit 34359738368 # 32G
ceph config set mds mds_bal_split_size 100000 # 更积极地碎片切分
目录分片:将极“胖”的目录进行层级切分(如 10k 文件/子目录一层),能显著降低单 MDS 压力。
8.3 客户端节点(训练机)
# 文件系统层面:noatime 已用;IO 层缓存适度保留
sysctl -w vm.vfs_cache_pressure=50
# NUMA 绑核与中断亲和(略,按现场绑 GPU 同 NUMA 的核)
9)基准与验收
简单的顺序读压(CephFS 背后 data pool):
# 4MB 顺序读取,线程 32
rados bench -p cephfs.ai.data 60 seq -t 32 --no-cleanup
# 随机读测试:
rados bench -p cephfs.ai.data 60 rand -t 64 --no-cleanup
实测(我现场的关键结果):
| 指标 | 优化前(NFS+NVMe 拼凑) | Ceph(初版) | Ceph(调优后) |
|---|---|---|---|
| 单训练节点聚合吞吐 | 620–750 MB/s | 1.1 GB/s | 1.45 GB/s |
| 集群聚合吞吐(8 节点) | ~4.5 GB/s | 8.7 GB/s | 11.6 GB/s |
| p95 读延迟(4MB) | 18–25 ms | 9–12 ms | 5–7 ms |
| 训练 samples/s | baseline | +22% | +31% |
| 失败重跑次数 | 高 | 中 | 低 |
10)监控与告警
ceph dashboard 开箱即用(OSD 延迟、PG 状态、MDS 热点)
Prometheus + Grafana:重点看 client ops, osd op latency, mds cache/queue, recovery/backfill。
警戒线:
- MDS heap 接近 mds_cache_memory_limit 且 ino 持续上升 → 目录热点或小文件风暴
- OSD apply_latency、commit_latency 抬头 → 盘子或网络
- PG degraded/undersized 长时间不消失 → 硬件/网络/参数
11)踩过的坑 & 现场解法
Jumbo MTU 不一致:一台训练机 MTU 1500,导致重传暴涨。
→ 统一 端到端 MTU=9000,并在交换机/宿主/NIC 全链路校验(ping -M do -s 8972)。
时钟漂移:某 OSD 主机 NTP 掉了,MON 报 clock skew,OSD 频繁 out/in。
→ 双冗余 NTP,makestep 开启;Ceph 侧不放宽限制,从根因修。
MDS 被小文件打爆:数据没打包直接扔 2 亿小文件。
→ 立刻改造 WebDataset tar;老数据后台重整;MDS max_mds=2、加大 mds_cache_memory_limit。
恢复打爆业务时段:一块 HDD 掉线,recovery 抢 IO。
→ 高峰期 osd set noscrub/nodeep-scrub + 收紧恢复并发;低峰放开;容量充足时选副本 3 保心安。
BIOS 省电策略:启用 C-State 深省电导致尾延迟高。
→ BIOS 设为 Performance,Linux intel_pstate=disable 或调到 performance governor。
RGW 后端桶分布单点热:某些 shard 热点明显。
→ RGW num_rados_handles 增大,桶分片数合理化;应用层随机化对象键前缀。
PG 过多:初始手算 PG 开太大,MON/MGR 内存飙升。
→ 打开 PG autoscaler,让它慢慢挪;新池先给 0 PG,再由 autoscaler 估。
fio 直测 CephFS 报错:direct=1 不生效。
→ 使用 rados bench/应用侧真实 workload 评测;RBD 用 fio。
12)容错与演练
拔一盘 HDD:训练运行中,业务 p95 读延迟从 6 ms 抬到 8–9 ms,可接受;恢复速率限流到夜间放开。
重启一台 OSD 宿主:副本池自动维持,PG 进入 degraded 又恢复,训练无感。
MDS 切换:kill active MDS,standby 2–4 秒接管,训练 DataLoader 偶有抖动但未报错。
13)配置清单(关键项备忘)
# 全局
ceph config set global ms_bind_port_min 6800
ceph config set global ms_bind_port_max 6900
# OSD
ceph config set osd osd_memory_target 8G
ceph config set osd bluestore_min_alloc_size_hdd 64K
# MDS
ceph fs set cephfs-ai max_mds 2
ceph config set mds mds_cache_memory_limit 32G
ceph osd pool set cephfs.ai.data pg_autoscale_mode on
# RGW(示意)
ceph orch apply rgw rgw.ai --placement="count:2 label:rgw" --port 8080
14)成本/容量/性能三角(规划建议)
| 方案 | 盘型 | 保护 | 成本/TB | 顺序读 | 随机小读 | 适用 |
|---|---|---|---|---|---|---|
| 副本池(本文) | HDD + NVMe DB | 副本 3 | 中 | 高 | 中 | 热数据训练 |
| EC 8+2 | HDD + NVMe DB | 纠删码 | 低 | 中 | 低 | 冷数据归档 |
| 全 NVMe | NVMe | 副本 3 | 高 | 极高 | 高 | 极致性能但成本高 |
15)收尾:那晚之后
凌晨 4:10,我们把最后一批 tar 分片从 S3(RGW)同步到了 CephFS。训练重新起跑,8 台训练机的 I/O 图线像被拉直的弓弦,GPU 利用率从 70% 往上走到 95%——那一刻我知道,I/O 这个短板被补上了。
后来几次数据增量夜,Ceph 像个沉默的水库:白天稳稳地放水给训练,晚上我们开闸导入,第二天照样跑。
写下这篇文档,用的是我在香港机房的汗和困意换来的细节。你完全可以照着这些参数和步骤落地,但我想提醒一句:先把数据形态和访问模式想清楚(小文件尽量打包、冷热分层),再用 Ceph 去托住你的吞吐、并发和可靠性。这样,等下一次凌晨两点报警响起,你就不会慌了。
附:快速 Checklist
- Public/Cluster 双网分离、MTU 一致(9000)
- Chrony/NTP 稳定,避免 clock skew
- HDD + NVMe DB/WAL 绑定比例合适(1 NVMe : 5–6 HDD)
- osd_memory_target、mds_cache_memory_limit 到位
- CephFS 多活 MDS(max_mds >= 2)
- PG autoscaler 打开,避免一次性爆 PG
- 高峰禁 scrub,低峰放开;恢复限速有节奏
- 训练数据 WebDataset/LMDB,减少小文件风暴
- RBD 存 checkpoint,CephFS 读样本,RGW 做导入
监控:client ops/latency、MDS cache、OSD recover/backfill
如果你也在香港机房跟 I/O 打仗,希望这篇能让你少熬几个夜。