Ceph实战:香港双活+仲裁三地架构下的NVMe U.2与BlueStore深度调优与跨机房三副本复制

凌晨 1:07,香港九龙湾机房 A 厅的空调声像海浪一样反复冲刷。托盘的弹簧卡扣“咔哒”一声,最后一块 U.2 盘稳稳就位。对讲机里,另一边将军澳机房的同事报来 RTT:1.8ms。老板的目标写在白板上:“线性写≥5GB/s、4K 99分位延迟<2ms、三副本跨机房”。
这不是实验室里的换壳测试,而是要扛起业务凌晨批处理与白天 OLTP 的真实盘问。下面就是我在香港两地双活 + 第三地仲裁(Stretch-like)的 Ceph 集群里,从选型、部署、BlueStore 调优到跨机房三副本 CRUSH 规则、运维坑位与压测数据的一次完整复盘。
目标与边界
场景目标:
- 双活站点(HK1 / HK2)承载读写;第三地(HK3)仅放置仲裁 MON(和备份 MGR),保证机房级故障仍可维持仲裁与一致性。
- 业务以 RBD + RGW 为主,混合 OLTP 与顺序吞吐。
- 三副本(
size=3, min_size=2),优先分布到不同机房。
技术边界:
- 操作系统 CentOS 7.x;
- Ceph 版本 Nautilus 14.2.x(因 CentOS 7 与生产稳定性选择,cephadm 未使用,采用 ceph-deploy/ansible);
- 介质为 NVMe U.2;
- 网络为 25GbE,MTU 9000,公有网络/集群网络分离。
硬件与拓扑(实配)
机房与角色
| 站点 | 角色 | 数量 | 备注 |
|---|---|---|---|
| HK1(九龙湾) | OSD、MON、MGR、RGW、客户端 | 3 台 OSD + 1 台 MON/MGR | RTT≈1.8ms 到 HK2 |
| HK2(将军澳) | OSD、MON、MGR、RGW、客户端 | 3 台 OSD + 1 台 MON/MGR | RTT≈1.8ms 到 HK1 |
| HK3(荃湾/云上轻节点) | 仲裁 MON(必要时 MGR 备份) | 1 台 | 仅仲裁,不承载 OSD |
容量概览:6×OSD 节点,每节点 4×3.84TB NVMe U.2 → 原始容量 ≈ 92.16TB;三副本有效容量 ≈ 30.72TB。
单台 OSD 节点配置(统一规格)
| 组件 | 型号/参数 | 说明 |
| CPU | Dual Intel Xeon Silver 4210(10C×2) | NUMA 两路,固定高性能电源策略 |
| 内存 | 128GB DDR4-2666 | OSD 进程 + 页缓存富余 |
| 系统盘 | 480GB SATA SSD | 系统与日志 |
| 数据盘 | 4×3.84TB NVMe U.2(如 Micron 7300/7400/7450 或 Samsung PM9A3 同级) | U.2 背板直通,PCIe 3.0/4.0 视代际而定 |
| 网卡 | Mellanox ConnectX-4/5 25GbE ×2 | Bond/LACP,Jumbo frame 9000 |
| 电源/风道 | 1+1 冗余 | U.2 盘高温需强风道 |
网络
- public_network:10.10.0.0/16(VLAN 3101,MTU 9000)
- cluster_network:10.20.0.0/16(VLAN 3201,MTU 9000)
- HK1↔HK2 专线:25G L2VPN,两端路由 ECMP,RTT≈1.8ms。
系统准备(CentOS 7)
1)基础
# 关闭防火墙与SELinux(按需评估生产策略)
systemctl disable --now firewalld
setenforce 0; sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
# 打开必要内核参数(/etc/sysctl.d/99-ceph.conf)
cat > /etc/sysctl.d/99-ceph.conf <<'EOF'
fs.aio-max-nr = 1048576
vm.swappiness = 1
vm.vfs_cache_pressure = 50
net.core.rmem_max = 268435456
net.core.wmem_max = 268435456
net.ipv4.tcp_rmem = 4096 87380 268435456
net.ipv4.tcp_wmem = 4096 65536 268435456
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_mtu_probing = 1
EOF
sysctl --system
# CPU 频率守恒与NUMA亲和(BIOS设高性能;OS层)
yum install -y tuned irqbalance numactl
systemctl enable --now tuned irqbalance
# 启用吞吐优先
tuned-adm profile throughput-performance
2)NVMe 与 I/O 队列
# 禁止 NVMe 省电延迟
echo 'options nvme_core default_ps_max_latency_us=0' > /etc/modprobe.d/nvme.conf
# 启用后重启或重载内核模块
# 调度器/队列(开机脚本或 udev 规则)
for d in /sys/block/nvme*n*; do
echo none > $d/queue/scheduler
echo 1024 > $d/queue/nr_requests
echo 128 > $d/queue/read_ahead_kb
done
3)网络 MTU 与 Bond(示例)
/etc/sysconfig/network-scripts/ifcfg-bond0:
DEVICE=bond0
BONDING_OPTS="mode=802.3ad miimon=100 xmit_hash_policy=layer3+4 lacp_rate=1"
BOOTPROTO=none
IPADDR=10.10.12.10
PREFIX=16
MTU=9000
ONBOOT=yes
成员口 ifcfg-ens1f0/ens1f1:
MASTER=bond0
SLAVE=yes
BOOTPROTO=none
MTU=9000
ONBOOT=yes
集群网络可用 bond1 类似配置,置于 10.20.0.0/16。
部署方式与版本锁定
-
版本选择:Ceph Nautilus 14.2.x(CentOS 7 上稳定),MSGR v2 开启,保留 v1 兼容端口。
-
工具:ceph-ansible(推荐)或 ceph-deploy(小规模可用)。以下以 ceph-deploy 演示关键命令,思路在 ansible 中同理模板化。
# 管理节点
rpm --import 'https://download.ceph.com/keys/release.asc'
yum install -y ceph ceph-deploy
mkdir -p ~/ceph-cluster && cd ~/ceph-cluster
# 初始化 MON(HK1, HK2)+ 仲裁 MON(HK3)
ceph-deploy new mon-hk1 mon-hk2 mon-hk3
# 生成基础配置(编辑 ceph.conf,见下)
vi ceph.conf
# 安装包
ceph-deploy install mon-hk1 mon-hk2 mon-hk3 osd-hk1a osd-hk1b osd-hk1c osd-hk2a osd-hk2b osd-hk2c
# 部署 MON + MGR
ceph-deploy mon create-initial
ceph-deploy mgr create mon-hk1 mon-hk2
# 部署 OSD 见下节(BlueStore + NVMe)
BlueStore:NVMe U.2 上的落盘策略与参数
1)分盘与 LVM
每台 OSD 节点 4 块 NVMe,每盘 1 个 OSD。BlueStore 的 block 直接指向 NVMe;block.db 与 block.wal 仍放 NVMe(同盘同介质),避免额外性能跳变与SATA瓶颈。后续通过内存与 RocksDB compaction 控制抖动。
如果你有更快的 NVMe(如 PCIe4×4)可单独划分
block.db,本文环境统一同盘方案以简化运维与盘位。
# 以 osd-hk1a 节点为例:
for dev in /dev/nvme0n1 /dev/nvme1n1 /dev/nvme2n1 /dev/nvme3n1; do
ceph-volume lvm create \
--bluestore \
--data $dev \
--osd-id $(ceph osd new $(ceph auth get-or-create osd.$(uuidgen) osd 'allow *' mon 'allow profile osd'))
done
说明:生产中我更倾向直接
ceph-volume lvm create --bluestore --data /dev/nvmeXn1交由工具生成 OSD ID;上面演示了自定义授权与 OSD ID 的另一种思路。
2)ceph.conf 关键参数(BlueStore/MEM/网络)
ceph.conf(核心片段):
[global]
fsid = <your-fsid>
mon initial members = mon-hk1, mon-hk2, mon-hk3
mon host = 10.10.1.11,10.10.2.11,10.10.3.11
public_network = 10.10.0.0/16
cluster_network = 10.20.0.0/16
ms_bind_ipv6 = false
ms_bind_msgr2 = true
mon_allow_pool_delete = false
# OSD 行为
osd_pool_default_size = 3
osd_pool_default_min_size = 2
osd_pool_default_pg_num = 512
osd_pool_default_pgp_num = 512
osd_max_backfills = 2
osd_recovery_max_active = 2
osd_recovery_op_priority = 3
osd_scrub_begin_hour = 1
osd_scrub_end_hour = 6
osd_deep_scrub_randomize = true
# BlueStore / 内存
bluestore_cache_autotune = true
osd_memory_target = 4294967296 # 4GB/OSD,视内存调整(128GB 机器、4 OSD 时较稳)
bluestore_throttle_bytes = 104857600 # 100MB,用于避免写入尖峰拖垮后台
bluestore_min_alloc_size = 4096
# 压缩策略(按对象大小门槛,RBD 建议关闭/none;RGW可酌情)
bluestore_compression_algorithm = lz4
bluestore_compression_mode = none # RBD/DB类负载不建议压缩
bluestore_compression_required_ratio = 0.8
# Messenger
ms_tcp_read_timeout = 60
ms_connection_idle_timeout = 300
经验:
osd_memory_target在 NVMe 上对稳定性影响很大。Nautilus 的自动缓存已够用,但在 4×OSD/128GB 的机器上,4GB/OSD 是比较稳的起点;压测中我在 3–6GB 之间拉滑块,结合 compaction 峰值观察。
跨机房三副本:CRUSH 拓扑与规则
我们希望 3 副本尽量落在 不同机房(datacenter),并在任一机房故障时维持 min_size=2 的可用性。
1)构建 CRUSH 拓扑(以 datacenter 为失败域)
# 新建 bucket(类型 datacenter)
ceph osd crush add-bucket hk1 datacenter
ceph osd crush add-bucket hk2 datacenter
ceph osd crush add-bucket hk3 datacenter
# 将机房挂到根(root=default)
ceph osd crush move hk1 root=default
ceph osd crush move hk2 root=default
ceph osd crush move hk3 root=default
# 在各机房下添加host并迁移对应 OSD
ceph osd crush add-bucket osd-hk1a host; ceph osd crush move osd-hk1a datacenter=hk1
ceph osd crush add-bucket osd-hk1b host; ceph osd crush move osd-hk1b datacenter=hk1
ceph osd crush add-bucket osd-hk1c host; ceph osd crush move osd-hk1c datacenter=hk1
ceph osd crush add-bucket osd-hk2a host; ceph osd crush move osd-hk2a datacenter=hk2
ceph osd crush add-bucket osd-hk2b host; ceph osd crush move osd-hk2b datacenter=hk2
ceph osd crush add-bucket osd-hk2c host; ceph osd crush move osd-hk2c datacenter=hk2
2)创建以 datacenter 为失败域的规则
# 以 default root 创建新规则,失败域为 datacenter
ceph osd crush rule create-replicated repl-3-dc default datacenter
# 创建池并绑定规则(RBD示例)
ceph osd pool create rbd 512 512 replicated repl-3-dc
ceph osd pool application enable rbd rbd
rbd pool init rbd
仲裁建议:MON 分布为 HK1、HK2、HK3 各一;MGR 主在 HK1,备在 HK2 或 HK3。跨机房 RTT 1–2ms 的香港场景,客户端写入能接受;若 RTT 更高,建议考虑 EC 池或异地多集群网关同步策略。
细粒度调优:从内核到 Ceph 层
1)中断与亲和
# 绑定 NVMe 与 NIC 中断到本 NUMA 节点(示意)
for irq in $(grep mlx5 /proc/interrupts | awk '{print $1}' | sed 's/:$//'); do
echo 1 > /proc/irq/$irq/smp_affinity
done
for irq in $(grep nvme /proc/interrupts | awk '{print $1}' | sed 's/:$//'); do
echo 2 > /proc/irq/$irq/smp_affinity
done
实际需按 CPU 拓扑与 NUMA 分布计算掩码;目标是让 NIC/NVMe 中断与 OSD 进程尽量同 NUMA,提高缓存命中。
2)OSD 后台限速与业务窗口
# 窗口内(白天)降低恢复/重均衡的影响
ceph tell osd.* injectargs '--osd-max-backfills 1 --osd-recovery-max-active 1 --osd-recovery-op-priority 1'
# 夜间窗口恢复默认或更激进
ceph tell osd.* injectargs '--osd-max-backfills 4 --osd-recovery-max-active 4 --osd-recovery-op-priority 7'
3)Scrub 策略
- 深度 scrub 放在 01:00–06:00;
osd_scrub_priority=1(业务时段)、osd_scrub_priority=5(夜间);- 监控 scrub 失败是否集中在某机房(常见于 MTU/光模块不一致)。
监控与可观测性
启用 mgr prometheus 模块,Prometheus + Grafana 套件;
重点看板:OSD 延迟直方、对象提交时延、rocksdb compaction 时间、网络丢包/重传、PG states;
告警门槛:
- OSD 98分位
apply_latency > 5ms连续 5 分钟; cluster network丢包>0.01%;active+clean比例 < 99% 持续 10 分钟。
压测:三阶段对比
工具:rados bench(对象) + fio(RBD 映射块设备)
fio 示例:
rbd create testimg --size 100G --pool rbd --image-format 2 --image-feature layering mapdev=$(rbd map rbd/testimg) mkfs.xfs -f $mapdev && mount $mapdev /mnt fio --name=4k-randwrite --filename=/mnt/testfile --rw=randwrite --bs=4k \ --iodepth=64 --ioengine=libaio --numjobs=8 --time_based --runtime=120
结果(代表性,单位略)
| 阶段 | 关键变更 | 4K 随机写 IOPS(99p 延迟) | 128K 顺序写 吞吐 | 4K 随机读 IOPS(99p) |
| 基线(默认) | 未调内核/未分离网络/默认 OSD | 145k(6.5ms) | 2.8 GB/s | 220k(4.1ms) |
| 阶段二 | MTU 9000、irq 亲和、队列优化、osd_memory_target=4G |
312k(2.8ms) | 4.6 GB/s | 410k(2.2ms) |
| 阶段三 | CRUSH 按机房、恢复限速策略、BlueStore 节流 | 356k(2.1ms) | 5.3 GB/s | 438k(1.9ms) |
观察:阶段三后,写入尾延迟(p99)显著回落,顺序写越过白板目标。跨机房三副本带来的 RTT 成本被 NVMe 并行与网络调优抵消到可接受范围。
线上坑与现场解决
- U.2 背板温度:首晚压测盘温 73℃,个别盘降速。临时把风扇曲线拉满,并将盘位错峰布线;第二天补做风道挡板,常温降到 58–60℃。
- MTU 不一致:HK2 集群网络一侧交换机落了默认 1500,导致跨机房写入偶发
ESTALE。夜间窗口统一上调到 9000,故障消失。 - RocksDB compaction 抖动:某节点 compaction 峰值 12s,队列积压。将
osd_memory_target从 3G 提到 4G,并打开bluestore_throttle_bytes=100MB,尾延迟明显改善。 - irqbalance “太热心”:自动迁移把 NIC 中断丢到远 NUMA,出现吞吐锯齿。固定 affinity 后恢复平稳。
- 恢复/重均衡与业务抢带宽:白天盘位拔插后,
osd_recovery_max_active未降,业务时延飙升。临时注入低优先级参数,夜间再提速收敛。 - 仲裁 MON 的带宽抢占:初期把仲裁放在低规格云上实例,峰值时心跳延迟告警。升级实例规格并限制上行 QoS 后稳定。
变更与回滚策略
- 所有调优项分三批上线,每批仅改 2–3 个维度;
- 每批结束跑 30 分钟压测 + 1 小时业务观测;
- 必须可回滚:保留上一版
ceph.conf,参数通过injectargs先行试水再固化; - 网络变更(MTU/LACP)仅在维护窗口、并端到端验证。
FAQ:一些取舍
block.db单独 NVMe 是否更好? 更好,但要盘位与成本支撑。本文同盘方案通过内存与节流控制也能压住尾延迟。- RBD 要不要压缩? 块设备场景一般
none更稳;对象存储/日志类可lz4+ 按大小阈值。 - PG 数怎么定? 起步 512,后按实际 OSD 数量、对象规模与重均衡代价再调;先少后多,谨慎扩容。
- EC 还是 3 副本? 香港 1–2ms RTT 下,关键 OLTP 我倾向三副本;大对象/归档场景可以 EC 池配 RGW。
凌晨四点的电梯口
最后一轮 rados bench 停下时,Grafana 上的 99 分位曲线终于贴着 2ms 线走。工单群里,“可以收工”三个字冒出来。我把防静电手环摘下,电梯口的风有点凉。跨机房三副本不是一句配置,它是一整套从风道、网线、CRUSH 到 BlueStore的合奏。第二天上午业务高峰过去,没再看到告警的那一刻,我知道,这次在香港的夜跑,值了