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

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

发布人:Minchunlin 发布时间:2025-09-26 10:09 阅读量:880

凌晨 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.dbblock.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 并行与网络调优抵消到可接受范围。

线上坑与现场解决

  1. U.2 背板温度:首晚压测盘温 73℃,个别盘降速。临时把风扇曲线拉满,并将盘位错峰布线;第二天补做风道挡板,常温降到 58–60℃。
  2. MTU 不一致:HK2 集群网络一侧交换机落了默认 1500,导致跨机房写入偶发 ESTALE。夜间窗口统一上调到 9000,故障消失。
  3. RocksDB compaction 抖动:某节点 compaction 峰值 12s,队列积压。将 osd_memory_target 从 3G 提到 4G,并打开 bluestore_throttle_bytes=100MB,尾延迟明显改善。
  4. irqbalance “太热心”:自动迁移把 NIC 中断丢到远 NUMA,出现吞吐锯齿。固定 affinity 后恢复平稳。
  5. 恢复/重均衡与业务抢带宽:白天盘位拔插后,osd_recovery_max_active 未降,业务时延飙升。临时注入低优先级参数,夜间再提速收敛。
  6. 仲裁 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的合奏。第二天上午业务高峰过去,没再看到告警的那一刻,我知道,这次在香港的夜跑,值了

目录结构
全文