Ceph 生产环境搭建 | 第 17 天:Ceph 集群扩容实战:OSD 动态添加与 CRUSH 重平衡

第 17/20 天

在 Ceph 生产环境的生命周期中,集群扩容是最常见的运维操作之一。随着业务数据量持续增长,初始规划的存储容量终将面临瓶颈,需要通过动态添加 OSD 节点来扩展存储空间。然而,扩容并非简单地把磁盘加进去——OSD 的加入会触发 CRUSH Map 的重新计算,导致大量 PG(Placement Group)在 OSD 之间迁移重平衡。如果不加以控制,重平衡产生的数据迁移流量可能挤占正常业务 I/O,造成客户端延迟飙升甚至服务降级。本篇将深入讲解 Ceph 集群扩容的架构原理、完整实战步骤、参数调优方法以及生产环境踩坑经验。

一、架构与原理:CRUSH 重平衡机制

1.1 OSD 添加对 CRUSH Map 的影响

Ceph 的数据分布依赖于 CRUSH(Controlled Replication Under Scalable Hashing)算法。CRUSH Map 定义了集群的层次化拓扑结构(Root → Row → Rack → Host → OSD),每个 OSD 都有权重值(weight),CRUSH 根据权重将 PG 映射到对应的 OSD 上。

当新 OSD 加入集群时,CRUSH Map 会自动更新该 OSD 所在层级的总权重。由于 CRUSH 算法是确定性哈希,权重变化会导致部分 PG 的映射结果发生偏移,这些 PG 需要从源 OSD 迁移到新 OSD 上——这就是 重平衡(Rebalancing) 过程。

K8s Logo

1.2 重平衡的数据流向

扩容时的数据迁移涉及以下状态机转换:

PG 状态 含义 说明
creating PG 正在创建 新 PG 初始化阶段
activating 激活中 PG 即将进入活跃状态
backfilling 全量回填 新 OSD 需要完整副本数据
backfill_wait 等待回填 排队中的回填任务
recovering 增量恢复 基于日志的差量同步
recover_wait 等待恢复 排队中的恢复任务
active+clean 正常状态 迁移完成

Backfill 是最重的操作——它将 PG 的完整数据复制到新 OSD 上,产生大量磁盘读和网络传输。Recovery 则是基于 PG Log 的增量同步,数据量较小但仍会消耗 I/O。

1.3 CRUSH 权重模型

每个 OSD 有两个关键权重参数:

  • weight(crush weight):基于磁盘实际容量计算,决定数据分布比例。一个 4TB 磁盘的 weight ≈ 4.0。
  • reweight(reweight):运维手动调整的负载权重,用于临时平衡不均匀的 OSD。范围 0.0~1.0,默认 1.0。

扩容时,新 OSD 的 crush weight 由 BlueStore 自动根据磁盘容量设置,但可以通过手动调整来控制数据流入速度。

1.4 扩容策略设计考量

在生产环境中,扩容策略需要考虑以下维度:

  1. 批量 vs 逐台添加:一次性加入大量 OSD 会引发峰值迁移流量;逐台添加更安全但耗时长。
  2. 故障域完整性:新节点必须纳入正确的 CRUSH 故障域(rack/row),避免副本集中。
  3. 重平衡节奏控制:通过 osd_max_backfills、osd_recovery_max_active 等参数限制并发度。
  4. 业务窗口选择:在低峰期执行扩容,减少对前端 I/O 的影响。

二、部署实战:OSD 动态添加与重平衡

2.1 环境准备

假设当前集群有 3 台 OSD 节点(osd-host-01/02/03),每节点 2 块 OSD,共 6 个 OSD。现在需要扩容到 4 台节点,新增 osd-host-04,配备 2 块 NVMe SSD。

💻 代码示例

# 查看当前集群状态

ceph -s

 

# 查看现有 OSD 树拓扑

ceph osd tree

 

# 确认新节点已加入集群并安装基础软件

# 新节点 osd-host-04 已通过 cephadm 加入集群(参考第 3 天 cephadm 引导)

ceph orch host ls

2.2 新节点纳入 CRUSH 拓扑

新 OSD 节点加入前,需要先在 CRUSH Map 中规划好其所属的故障域。假设集群使用 rack 级别作为副本隔离域,新节点位于 rack-04。

💻 代码示例

# 创建 CRUSH rack bucket(如果尚未存在)

ceph osd crush add-bucket rack-04 rack

 

# 将 rack-04 挂载到默认 root 下

ceph osd crush move rack-04 root=default

 

# 在 rack-04 下创建 host bucket

ceph osd crush add-bucket osd-host-04 host

 

# 将 osd-host-04 移入 rack-04

ceph osd crush move osd-host-04 rack=rack-04

 

# 验证 CRUSH 拓扑结构

ceph osd tree

执行后 CRUSH 树应显示 rack-04/osd-host-04 节点,此时尚无 OSD 挂入。

2.3 添加新 OSD

使用 cephadm 自动发现并添加 OSD。Cephadm 会扫描节点上的可用裸盘,自动创建 BlueStore OSD 并纳入 CRUSH Map。

💻 代码示例

# 方式一:cephadm 自动发现并添加所有可用磁盘

ceph orch daemon add osd osd-host-04:

 

# 方式二:指定具体磁盘路径(更精确)

ceph orch daemon add osd osd-host-04:/dev/nvme0n1

ceph orch daemon add osd osd-host-04:/dev/nvme1n1

 

# 查看 OSD 添加进度

ceph orch daemon status

 

# 确认新 OSD 已加入并处于 up 状态

ceph osd tree

新 OSD 加入后,Ceph 会自动为其设置 crush weight(基于磁盘容量),并立即开始 backfill 过程。

2.4 控制重平衡速率

扩容触发的重平衡是 I/O 密集型操作。在生产环境中,必须限制并发度以保护正常业务。以下参数可在运行时动态调整:

💻 代码示例

# 限制每个 OSD 的最大 backfill 并发数(默认 1,生产建议 1-2)

ceph tell osd.* injectargs '–osd_max_backfills=2'

ceph tell osd.* injectargs '–osd_recovery_max_backfills=2'

 

# 限制恢复操作的最大并发活跃数(默认 3,扩容时可提升至 5-6)

ceph tell osd.* injectargs '–osd_recovery_max_active=5'

 

# 调整恢复操作的 I/O 优先级(默认 recovery_op_priority=3,客户端=63)

# 值越大优先级越高,扩容时保持低优先级让客户端 I/O 优先

ceph tell osd.* injectargs '–osd_recovery_op_priority=3'

 

# 设置恢复睡眠时间(微秒),增加延迟以降低 I/O 占用

ceph tell osd.* injectargs '–osd_recovery_sleep=0.2'

 

# 查看当前 PG 迁移进度

ceph -w

ceph pg dump pgs_brief | grep -E 'backfill|recover'

2.5 CRUSH 权重微调

如果新 OSD 数据流入过快导致前端延迟波动,可以临时降低其 crush weight,让数据以更平滑的速度迁入:

💻 代码示例

# 查看所有 OSD 的当前权重

ceph osd tree | grep -E 'osd.|weight'

 

# 临时降低新 OSD 的 reweight(从默认 1.0 降到 0.5)

ceph osd reweight osd.6 0.5

ceph osd reweight osd.7 0.5

 

# 使用 reweight-by-utilization 自动平衡(基于 PG 分布)

ceph osd reweight-by-utilization

 

# 使用 test-reweight-by-utilization 先预览(不实际修改)

ceph osd test-reweight-by-utilization

 

# 重平衡完成后恢复 reweight 到 1.0

ceph osd reweight osd.6 1.0

ceph osd reweight osd.7 1.0

2.6 监控重平衡进度

💻 代码示例

# 实时监控集群整体状态和 PG 迁移

ceph -w

 

# 查看 PG 分布均匀度

ceph pg dump pgs_brief | awk '{print $2}' | sort | uniq -c | sort -rn

 

# 查看每个 OSD 的 PG 数量

ceph osd df | head -20

 

# 查看恢复进度统计

ceph df

 

# 查看具体某个 PG 的状态详情

ceph pg ls | grep backfill

ceph pg ls | grep recover

2.7 扩容后集群验证

重平衡完成后(所有 PG 回到 active+clean),执行完整验证:

💻 代码示例

# 集群健康状态应为 HEALTH_OK

ceph health detail

 

# 确认所有 PG 均为 active+clean

ceph pg stat

 

# 验证 OSD 权重分布均匀

ceph osd df tree

 

# 检查集群总容量已增长

ceph df

 

# 运行 RBD 性能基准测试验证新节点正常工作

rbd bench-write test-pool/test-image –io-size 4M –io-total 1G –io-threads 4

三、配置参数详解

3.1 重平衡核心参数

参数 默认值 生产建议 说明
osd_max_backfills 1 1-2 单个 OSD 同时接受的 backfill 数
osd_recovery_max_backfills 1 2-3 单个 OSD 同时发起的 backfill 数
osd_recovery_max_active 3 5-6 每个 OSD 的活跃恢复请求数
osd_recovery_op_priority 3 3 恢复操作优先级(客户端=63)
osd_recovery_sleep 0 0.1-0.5 恢复操作间隔睡眠时间(秒)
osd_recovery_max_chunk 8MB 8-16MB 单次恢复数据块大小
osd_backfill_full_ratio 0.85 0.85 OSD 使用率超过此值时拒绝 backfill

3.2 持久化配置

通过 injectargs 修改的参数是临时的(OSD 重启后失效),生产环境需要写入配置文件持久化:

💻 代码示例

# ceph.conf 或 cephadm 配置覆盖

# 使用 ceph config set 持久化(推荐)

# 语法:ceph config set <class> <parameter> <value>

 

ceph config set osd osd_max_backfills 2

ceph config set osd osd_recovery_max_active 5

ceph config set osd osd_recovery_sleep 0.2

 

# 验证配置已持久化

ceph config dump | grep -E 'max_backfill|max_active|recovery_sleep'

 

# 查看特定 OSD 的生效配置

ceph config dump | grep osd.6

四、生产环境注意事项与踩坑提示

4.1 分批次添加 OSD

生产环境切忌一次性添加大量 OSD。假设集群有 30 个 OSD,一次性加入 10 个会导致近 25% 的 PG 需要迁移,产生巨大的网络和磁盘 I/O 压力。

推荐做法:每次添加 1-2 个 OSD,等待重平衡完成(active+clean)后再添加下一批。使用脚本自动化批次添加:

💻 代码示例

#!/bin/bash

# batch_add_osd.sh — 分批添加 OSD 脚本

HOST="osd-host-04"

DISKS=("/dev/nvme0n1" "/dev/nvme1n1")

 

for disk in "${DISKS[@]}"; do

echo ">>> Adding OSD: $HOST:$disk"

ceph orch daemon add osd "$HOST:$disk"

 

echo ">>> Waiting for backfill to complete…"

while true; do

status=$(ceph health | head -1)

if [[ "$status" == "HEALTH_OK" ]]; then

echo ">>> Cluster healthy, proceeding to next OSD"

break

fi

echo ">>> Current status: $status, waiting 60s…"

sleep 60

done

done

echo ">>> All OSDs added successfully"

4.2 CRUSH 故障域验证

新 OSD 必须正确归属到预期的故障域中。如果 rack 信息错误,可能导致同一副本的多个 PG 落在同一 rack 上,丧失容灾能力。

💻 代码示例

# 验证某个 PG 的副本分布在不同的 rack/host

ceph pg map 1.0

# 输出应显示 osd 位于不同 host 或 rack

 

# 使用 crushtool 检查 CRUSH 映射规则

ceph osd getcrushmap -o /tmp/crushmap.bin

crushtool -d /tmp/crushmap.bin -o /tmp/crushmap.txt

# 检查 /tmp/crushmap.txt 中的 ruleset 确保选择策略正确

4.3 踩坑:reweight 忘记恢复

使用 ceph osd reweight 临时降低新 OSD 权重后,必须在重平衡完成后恢复到 1.0。否则该 OSD 长期处于低权重状态,导致数据分布不均,其他 OSD 提前达到 full ratio。

检查方法:

💻 代码示例

# 查看是否有 OSD 的 reweight 不为 1.0

ceph osd tree | awk '$1 ~ /osd./ {print $0}'

# 确认所有 OSD 的 REWEIGHT 列均为 1.00000

4.4 踩坑:full ratio 与扩容冲突

如果集群在接近 osd_full_ratio(默认 0.85)时才扩容,新 OSD 加入后 backfill 操作需要从满载 OSD 读取数据,但满载 OSD 可能因 osd_backfill_full_ratio(默认 0.85)拒绝 backfill 请求,导致迁移卡住。

解决方案:

💻 代码示例

# 临时提高 backfill full ratio

ceph tell osd.* injectargs '–osd_backfill_full_ratio=0.90'

ceph tell osd.* injectargs '–osd_failsafe_full_ratio=0.97'

 

# 扩容完成后恢复默认值

ceph tell osd.* injectargs '–osd_backfill_full_ratio=0.85'

ceph tell osd.* injectargs '–osd_failsafe_full_ratio=0.95'

最佳实践:集群使用率达到 70% 时就应启动扩容,不要等到 85%+ 才行动。

4.5 网络带宽控制

扩容时 backfill 流量走集群网络(cluster network)。如果集群网络带宽有限(如 10Gbps),大量并发 backfill 可能打满网络带宽。建议在低峰期执行扩容,或通过 osd_recovery_sleep 增加延迟来降低网络压力。

💻 代码示例

# 监控集群网络带宽(在 OSD 节点上执行)

iftop -i <cluster_nic>

 

# 或使用 sar 监控

sar -n DEV 5 | grep <cluster_nic>

五、常见问题

Q1: 新 OSD 加入后一直是 down 状态,怎么办?

A: 首先检查新节点的磁盘是否为裸盘(无分区、无文件系统)。BlueStore 要求独占整块裸盘。如果磁盘已有分区表,需要先清除:

💻 代码示例

# 在新节点上检查磁盘

lsblk -f

# 如果磁盘有分区,用 wipefs 清除(注意确认磁盘正确!)

wipefs -a /dev/nvme0n1

sgdisk –zap-all /dev/nvme0n1

# 重新添加

ceph orch daemon add osd osd-host-04:/dev/nvme0n1

同时检查 cephadm 是否能 SSH 到新节点:ceph orch host ls 确认节点状态。

Q2: 重平衡进度很慢,正常吗?

A: 重平衡速度取决于磁盘性能和网络带宽。HDD OSD 的 backfill 速度通常为 20-50MB/s,NVMe SSD 可达 200-500MB/s。如果感觉异常慢,检查以下几点:

  • osd_max_backfills 和 osd_recovery_max_active 是否被设置过低
  • 集群网络带宽是否被打满
  • OSD 磁盘是否有其他高 I/O 负载(如同时在进行 scrub)
  • 暂停 scrub 操作:ceph osd set noscrub; ceph osd set nodeep-scrub,重平衡完成后再解除

Q3: 扩容后 PG 分布不均匀,部分 OSD 的 PG 数明显偏多怎么办?

A: 使用 ceph osd reweight-by-utilization 命令自动根据 PG 分布和磁盘使用率重新调整 OSD 的 reweight。该命令会自动降低过载 OSD 的权重、提高轻载 OSD 的权重。可以多次执行直到分布均匀。如果仍然不均,检查 CRUSH Map 的权重是否与实际磁盘容量匹配。

六、总结

本篇深入讲解了 Ceph 集群扩容的全流程:从 CRUSH 重平衡的架构原理到 OSD 动态添加的完整实战操作,再到重平衡速率控制和权重微调。核心要点回顾:

  1. 理解 CRUSH 机制:扩容本质是权重变化触发 PG 重新映射,backfill 是最重的迁移操作。
  2. 分批添加 OSD:每次 1-2 个,等待 active+clean 后再加下一批。
  3. 控制重平衡节奏:通过 osd_max_backfills、osd_recovery_max_active、osd_recovery_sleep 限制并发度。
  4. 及时恢复 reweight:临时降低的权重必须在重平衡完成后恢复为 1.0。
  5. 提前规划扩容:集群使用率达到 70% 就应启动扩容,不要等到接近 full ratio。
  6. 验证故障域:新 OSD 必须正确归入 CRUSH 拓扑的对应 rack/host,确保副本隔离。

集群扩容是 Ceph 运维中风险较高的操作,但只要遵循分批添加、控制速率、验证故障域三大原则,就能在业务无感知的前提下平滑完成容量扩展。

下期预告

明天(第 18 天)我们将探讨 「Ceph 高可用与容灾设计:多副本、跨机房与异地灾备」——从单集群高可用到跨数据中心容灾架构的完整设计方案,包括 stretch cluster、多活 RGW、Ceph 的 stretched mode 等企业级容灾技术。

系列目录

微信公众号二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像 - 恒星
欢迎您留下宝贵的见解!
提交
头像 - 恒星

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容