一、概述
1.1 背景介绍
去年我们的 Ceph 集群从 500TB 扩容到 1.2PB 时,经历了一次"事故级"的扩容体验。原本计划周末完成的扩容,结果拖了整整一周,期间业务延迟飙升 10 倍,差点酿成 P0 故障。这次惨痛经历让我深刻理解了 Ceph 数据重平衡的机制,也总结出一套相对稳妥的扩容方案。
Ceph 是一个分布式存储系统,其核心特性之一是数据的自动重平衡(Rebalancing)。当集群拓扑发生变化(添加/删除 OSD)时,CRUSH 算法会重新计算数据的分布位置,导致大量数据迁移。如果不加以控制,这个过程会消耗大量带宽和 IO 资源,严重影响前端业务。
1.2 技术特点
- CRUSH 算法驱动:Ceph 使用 CRUSH 算法计算数据存放位置,扩容时会触发重新计算,部分数据需要迁移到新节点
- 后台自动执行:数据重平衡由 Ceph 自动执行,默认配置下会尽可能快地完成迁移,不考虑业务影响
- 可控性有限:虽然可以调整重平衡速度,但完全暂停会导致数据分布不均,同样影响性能
- 累积效应明显:一次性添加多个 OSD,数据迁移量会叠加,对集群的冲击成倍增加
1.3 适用场景
- 场景一:生产环境 Ceph 集群容量扩展,需要在不影响业务的前提下完成
- 场景二:硬件升级换代,需要逐步替换旧 OSD 并添加新 OSD
- 场景三:集群性能优化,通过调整 OSD 分布改善数据均衡性
- 场景四:机房迁移或多机房部署,涉及大规模数据重分布
1.4 环境要求
| 组件 |
版本要求 |
说明 |
| Ceph |
Quincy (17.x) 或 Reef (18.x) |
本文基于 Quincy 版本,Pacific 及更早版本部分参数不同 |
| 操作系统 |
Ubuntu 22.04 / Rocky Linux 9 |
需要内核 5.4+ 以获得更好的 BlueStore 性能 |
| 网络 |
10GbE 以上,建议 25GbE |
公网/集群网分离,扩容期间重平衡走集群网 |
| 内存 |
每 OSD 8GB+ |
BlueStore 缓存需要足够内存 |
二、详细步骤
2.1 准备工作
2.1.1 扩容前评估
在动手之前,必须搞清楚几个关键问题:
# 查看当前集群状态
ceph status
ceph health detail
# 检查当前 OSD 数量和分布
ceph osd tree
# 查看当前数据分布情况
ceph osd df tree
# 计算当前集群使用率
ceph df detail
# 检查 PG 状态,确保没有异常
ceph pg stat
ceph pg dump_stuck
关键指标确认:
- ✅ 集群健康状态必须是
HEALTH_OK
- ✅ 没有处于
degraded、recovering、backfilling 状态的 PG
- ✅ 没有处于
down 状态的 OSD
- ✅ 集群使用率低于 70%(留出重平衡缓冲空间)
2.1.2 规划扩容批次
这是最关键的一步。根据我的经验,单批次添加的 OSD 数量不应超过总 OSD 数量的 10-15%。
# 假设当前有 100 个 OSD,计划添加 20 个 OSD
# 建议分 2-3 批次进行:
# 批次1:添加 8 个 OSD
# 批次2:添加 8 个 OSD
# 批次3:添加 4 个 OSD
# 估算数据迁移量
# 假设当前数据量 500TB,100 个 OSD
# 添加 8 个 OSD 后,理论上需要迁移的数据:
# 500TB * (8 / 108) ≈ 37TB
2.1.3 调整重平衡参数(扩容前)
在添加 OSD 之前,先调整重平衡参数,限制数据迁移速度:
# 设置较低的重平衡速度参数
# osd_recovery_max_active:每个 OSD 并发恢复操作数
ceph config set osd osd_recovery_max_active 1
# osd_recovery_max_active_hdd:HDD 专用参数(如果是 HDD)
ceph config set osd osd_recovery_max_active_hdd 1
# osd_recovery_max_active_ssd:SSD 专用参数
ceph config set osd osd_recovery_max_active_ssd 2
# osd_max_backfills:每个 OSD 并发 backfill 数
ceph config set osd osd_max_backfills 1
# osd_recovery_sleep:恢复操作间隔(毫秒),增加此值降低恢复速度
ceph config set osd osd_recovery_sleep_hdd 0.1
ceph config set osd osd_recovery_sleep_ssd 0
# osd_recovery_priority:恢复操作优先级(1-63,数值越小优先级越低)
ceph config set osd osd_recovery_priority 1
2.2 核心配置
2.2.1 设置 OSD 初始权重为 0
这是避免数据风暴的关键技巧。新添加的 OSD 初始权重设为 0,不参与数据分布:
# 添加新 OSD 时使用 --crush-initial-weight=0 参数
# 使用 cephadm 部署时的配置
ceph orch daemon add osd <host>:<device> --crush-initial-weight=0
# 或者在 OSD 添加后立即设置权重为 0
ceph osd crush reweight osd.<id> 0
说明:权重为 0 的 OSD 不会被 CRUSH 算法选中存放数据,这样可以让我们控制数据迁移的节奏。
2.2.2 逐步提升 OSD 权重
添加 OSD 后,逐步提升权重,控制数据迁移量:
# 假设新添加了 osd.100 到 osd.107(共 8 个)
# 目标权重为 1.0(对应 1TB 磁盘)
# 第一轮:权重提升到 0.1
for i in {100..107}; do
ceph osd crush reweight osd.$i 0.1
done
# 等待重平衡完成
watch -n 5 'ceph status | grep -E "recovery|backfill|misplaced"'
# 确认无重平衡活动后,进行第二轮
for i in {100..107}; do
ceph osd crush reweight osd.$i 0.3
done
# 重复上述过程,逐步提升到 0.5 -> 0.7 -> 0.9 -> 1.0
参数说明:
- 权重提升幅度建议不超过 0.2,步子太大会导致瞬间大量数据迁移
- 每轮权重提升后,必须等待重平衡完成再进行下一轮
- 夜间业务低峰期可以适当加大步长,提高效率
2.2.3 使用 noout 标志保护
在扩容期间,设置 noout 标志防止短暂的网络抖动导致 OSD 被标记为 out:
# 设置 noout 标志
ceph osd set noout
# 扩容完成后取消
ceph osd unset noout
# 也可以针对特定 OSD 设置
ceph osd add-noout osd.100
ceph osd rm-noout osd.100
2.3 启动和验证
2.3.1 监控重平衡进度
# 实时监控集群状态
watch -n 2 'ceph status'
# 查看重平衡详情
ceph progress
# 查看 PG 恢复状态
ceph pg stat
ceph pg dump_stuck recovering
# 查看各 OSD 的恢复任务
ceph daemon osd.0 perf dump | grep -E "recovery|backfill"
2.3.2 监控业务影响
# 监控 OSD 延迟
ceph osd perf
# 监控 IOPS 和吞吐量
ceph daemon osd.0 perf dump | jq '.osd.op_r, .osd.op_w'
# 使用 rados bench 测试当前性能(慎用,会增加负载)
# rados bench -p test-pool 60 write --no-cleanup
# 检查慢请求
ceph daemon osd.0 dump_ops_in_flight
ceph daemon osd.0 dump_blocked_ops
三、示例代码和配置
3.1 完整配置示例
3.1.1 扩容前的参数配置
# 文件路径:保存为 ceph_expansion_config.sh
#!/bin/bash
# Ceph 集群扩容前配置脚本
echo "=== 设置重平衡限速参数 ==="
# 降低恢复操作的并发度
ceph config set osd osd_recovery_max_active 1
ceph config set osd osd_recovery_max_active_hdd 1
ceph config set osd osd_recovery_max_active_ssd 2
ceph config set osd osd_max_backfills 1
# 设置恢复操作的优先级和间隔
ceph config set osd osd_recovery_priority 1
ceph config set osd osd_recovery_sleep_hdd 0.1
ceph config set osd osd_recovery_sleep_ssd 0.02
# 限制恢复操作的带宽
ceph config set osd osd_recovery_max_bytes 52428800 # 50MB/s
# 设置 noout 防止误判
ceph osd set noout
echo "=== 当前配置 ==="
ceph config dump | grep -E "recovery|backfill"
echo "=== 集群状态 ==="
ceph status
3.1.2 自动化扩容脚本
#!/bin/bash
# Ceph OSD 权重渐进式调整脚本
# 文件名:gradual_weight_adjust.sh
# 配置参数
OSD_IDS="100 101 102 103 104 105 106 107" # 新添加的 OSD ID 列表
TARGET_WEIGHT=1.0 # 目标权重
STEP=0.2 # 每次提升的权重步长
CHECK_INTERVAL=30 # 检查间隔(秒)
MAX_WAIT_TIME=3600 # 单轮最大等待时间(秒)
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 检查是否有活跃的重平衡
check_rebalance_active() {
local status=$(ceph status 2>/dev/null)
if echo "$status" | grep -qE "recovery|backfill|misplaced|degraded"; then
return 0 # 有活跃重平衡
else
return 1 # 无活跃重平衡
fi
}
# 等待重平衡完成
wait_for_rebalance() {
local waited=0
log "等待重平衡完成..."
while check_rebalance_active; do
if [ $waited -ge $MAX_WAIT_TIME ]; then
log "警告:等待超时,但仍有重平衡活动"
return 1
fi
sleep $CHECK_INTERVAL
waited=$((waited + CHECK_INTERVAL))
# 显示进度
local progress=$(ceph progress json 2>/dev/null | jq -r '.events[0].progress // 0')
log "重平衡进度: ${progress}%, 已等待: ${waited}s"
done
log "重平衡完成"
return 0
}
# 获取当前权重
get_current_weight() {
local osd_id=$1
ceph osd crush tree --format json 2>/dev/null | \
jq -r ".nodes[] | select(.id == ${osd_id}) | .crush_weight"
}
# 主流程
main() {
log "开始渐进式 OSD 权重调整"
log "目标 OSD: $OSD_IDS"
log "目标权重: $TARGET_WEIGHT, 步长: $STEP"
# 计算轮次
local rounds=$(echo "scale=0; $TARGET_WEIGHT / $STEP" | bc)
log "预计需要 $rounds 轮调整"
for round in $(seq 1 $rounds); do
local new_weight=$(echo "scale=1; $STEP * $round" | bc)
log "=== 第 $round 轮:调整权重到 $new_weight ==="
for osd_id in $OSD_IDS; do
local current=$(get_current_weight $osd_id)
log "调整 osd.$osd_id: $current -> $new_weight"
ceph osd crush reweight osd.$osd_id $new_weight
done
# 等待本轮重平衡完成
sleep 10 # 给 Ceph 一点时间开始重平衡
if ! wait_for_rebalance; then
log "警告:第 $round 轮等待超时,继续下一轮"
fi
log "第 $round 轮完成"
echo ""
done
log "=== 所有调整完成 ==="
ceph osd df tree
}
# 执行
main
3.2 实际应用案例
案例一:500TB 扩容到 800TB
场景描述:生产环境 Ceph 集群,原有 60 个 OSD(每个 8TB HDD),需要添加 36 个 OSD,实现从 500TB 到 800TB 的扩容。业务是在线视频点播,对延迟敏感,扩容期间不能影响用户体验。
实现步骤:
1. 扩容前准备
# 检查集群状态
ceph status
# 确认 HEALTH_OK,无异常 PG
# 设置限速参数
ceph config set osd osd_recovery_max_active 1
ceph config set osd osd_max_backfills 1
ceph config set osd osd_recovery_max_bytes 31457280 # 30MB/s
ceph osd set noout
2. 分批添加 OSD
# 第一批:添加 12 个 OSD(osd.60 到 osd.71)
# 初始权重为 0
for i in {60..71}; do
ceph orch daemon add osd node$((i-60)).storage.local:/dev/sdb --crush-initial-weight=0
done
# 渐进式提升权重
for weight in 0.1 0.3 0.5 0.7 0.9 1.0; do
for i in {60..71}; do
ceph osd crush reweight osd.$i $weight
done
echo "权重调整到 $weight,等待重平衡..."
while ceph status | grep -qE "recovery|backfill"; do
sleep 60
done
echo "重平衡完成,继续下一轮"
done
# 等待完全稳定后,进行第二批
# 重复上述过程
运行结果:
扩容过程数据:
- 总耗时:5 天
- 业务延迟影响:P99 延迟从 50ms 上升到 80ms(可接受范围内)
- 数据迁移量:约 240TB
- 每批次迁移耗时:约 40 小时
- 扩容期间无告警,无用户投诉
案例二:紧急扩容(不推荐但有时不得不做)
场景描述:集群使用率已经到了 85%,必须在 48 小时内完成扩容,否则会触发 nearfull 状态。这种情况下需要在风险可控的前提下加快进度。
实现步骤:
1. 评估风险和选择窗口
# 分析业务流量,选择低峰期
# 假设凌晨 2-6 点是最低峰期
# 设置较激进的限速参数
ceph config set osd osd_recovery_max_active 3
ceph config set osd osd_max_backfills 2
ceph config set osd osd_recovery_max_bytes 104857600 # 100MB/s
2. 一次性添加所有 OSD 但分步调权重
# 添加所有 OSD,初始权重 0
ceph orch apply osd --all-available-devices --crush-initial-weight=0
# 低峰期快速提权(大步长)
# 凌晨 2 点
for i in $(ceph osd ls); do
weight=$(ceph osd crush tree --format json | jq -r ".nodes[] | select(.id == $i) | .crush_weight")
if [ "$weight" == "0" ]; then
ceph osd crush reweight osd.$i 0.5
fi
done
# 凌晨 5 点(如果重平衡基本完成)
for i in $(ceph osd ls); do
weight=$(ceph osd crush tree --format json | jq -r ".nodes[] | select(.id == $i) | .crush_weight")
if [ "$weight" == "0.5" ]; then
ceph osd crush reweight osd.$i 1.0
fi
done
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 容量规划
预留扩容缓冲:集群使用率不要超过 70%,留出足够空间应对扩容期间的数据迁移
# 定期检查容量告警
ceph df detail
# 设置告警阈值
ceph config set global mon_osd_full_ratio 0.95
ceph config set global mon_osd_nearfull_ratio 0.85
ceph config set global mon_osd_backfillfull_ratio 0.90
按故障域扩容:
- 新 OSD 应该均匀分布在不同的 host/rack/datacenter
- 避免单个故障域容量过大
- 确保数据副本分布符合预期
4.1.2 网络优化
分离公网和集群网:确保重平衡流量走集群网,不影响客户端访问
# 检查网络配置
ceph config get osd public_network
ceph config get osd cluster_network
# 配置示例
ceph config set global public_network 192.168.1.0/24
ceph config set global cluster_network 192.168.2.0/24
启用巨型帧:减少网络开销
# 在所有存储节点上配置
ip link set eth1 mtu 9000
4.1.3 时间窗口选择
- 业务低峰期操作:权重调整尽量在业务低峰期进行
- 避免关键业务窗口:电商大促、财务结算等关键时期不要扩容
- 分时段调整:白天设置较低的恢复速度,夜间提高速度
# 可以使用 cron 实现分时段调整
# 白天限速(8:00)
0 8 * * * ceph config set osd osd_recovery_max_active 1
# 夜间加速(22:00)
0 22 * * * ceph config set osd osd_recovery_max_active 3
4.2 注意事项
4.2.1 配置注意事项
⚠️ 警告:以下操作可能导致数据丢失或集群不可用,务必谨慎
- 注意事项一:永远不要在集群状态非
HEALTH_OK 时开始扩容
- 注意事项二:不要同时进行多种变更操作(如扩容同时调整 CRUSH 规则)
- 注意事项三:确保新 OSD 的硬件配置与现有 OSD 一致,避免性能不均衡
4.2.2 常见错误
| 错误现象 |
原因分析 |
解决方案 |
| OSD 添加后立即 down |
新 OSD 磁盘或网络问题 |
检查磁盘健康状态、网络连通性、日志 |
| 重平衡速度过慢 |
限速参数设置过于保守 |
在业务允许范围内适当提高恢复参数 |
| 业务延迟飙升 |
重平衡占用过多 IO |
降低恢复参数,考虑暂停重平衡 |
| PG 长时间处于 remapped 状态 |
OSD 权重或 CRUSH 规则问题 |
检查 CRUSH 规则,确认 OSD 权重正确 |
| 扩容后数据不均衡 |
CRUSH 权重未正确设置 |
使用 ceph osd reweight-by-utilization 调整 |
4.2.3 紧急止血
当扩容过程中出现严重问题时,需要紧急止血:
# 暂停所有恢复操作
ceph osd set norecover
ceph osd set nobackfill
# 检查问题后,如果需要继续
ceph osd unset norecover
ceph osd unset nobackfill
# 如果某个 OSD 有问题,可以先将其权重设为 0
ceph osd crush reweight osd.<problem_id> 0
五、故障排查和监控
5.1 故障排查
5.1.1 日志查看
# 查看 OSD 日志
journalctl -u ceph-osd@0 -f
# 查看特定时间段的日志
journalctl -u ceph-osd@0 --since "2024-01-01 10:00:00" --until "2024-01-01 12:00:00"
# 查看 MON 日志(监控 CRUSH 变更)
journalctl -u ceph-mon@mon01 | grep -i crush
# 查看集群事件
ceph log last 100
5.1.2 常见问题排查
问题一:OSD 添加成功但数据迁移不开始
# 诊断命令
ceph osd tree # 确认 OSD 状态为 up+in
ceph osd crush tree # 确认 OSD 在正确的 CRUSH 位置
ceph osd df # 确认权重不为 0
ceph pg dump_stuck # 检查是否有 stuck PG
解决方案:
- 确认 OSD 权重大于 0
- 检查 CRUSH 规则是否将新 OSD 纳入
- 检查是否设置了
norecover/nobackfill 标志
问题二:重平衡过程中 OSD 频繁 flapping
# 诊断命令
ceph health detail
ceph osd dump | grep "last_clean_begin"
dmesg | grep -i "osd\|ceph"
解决方案:
- 检查网络稳定性,是否有丢包
- 检查磁盘是否有 slow ops
- 适当增加
mon_osd_min_down_reporters 和 mon_osd_down_out_interval
问题三:扩容后性能下降明显
- 症状:IOPS 下降 30% 以上,延迟增加
- 排查:检查数据分布是否均衡,是否有热点 OSD
- 解决:使用
ceph osd reweight-by-utilization 调整权重
# 查看 OSD 使用率差异
ceph osd df tree
# 自动调整权重(会模拟执行,需要确认)
ceph osd reweight-by-utilization
ceph osd test-reweight-by-utilization
# 手动调整特定 OSD
ceph osd reweight osd.<id> <weight> # 注意:这是 reweight 不是 crush reweight
5.1.3 深入诊断
# 查看单个 OSD 的详细状态
ceph daemon osd.0 status
# 查看 OSD 的 perf counter
ceph daemon osd.0 perf dump
# 查看 PG 分布
ceph pg dump | awk '/^[0-9]/ {print $1,$15,$16}' | sort -k2 -n
# 查看恢复操作详情
ceph pg dump | grep -E "recovering|backfilling"
5.2 性能监控
5.2.1 关键指标监控
# 实时监控脚本
watch -n 5 'echo "=== 集群状态 ==="
ceph status | head -20
echo ""
echo "=== OSD 延迟 (ms) ==="
ceph osd perf | head -10
echo ""
echo "=== 恢复进度 ==="
ceph progress
echo ""
echo "=== IO 统计 ==="
ceph daemon osd.0 perf dump | jq ".osd | {op_r_latency: .op_r_latency, op_w_latency: .op_w_latency}"'
5.2.2 监控指标说明
| 指标名称 |
正常范围 |
告警阈值 |
说明 |
| op_r_latency |
< 10ms (SSD) / < 50ms (HDD) |
2x 基线 |
读操作延迟 |
| op_w_latency |
< 20ms (SSD) / < 100ms (HDD) |
2x 基线 |
写操作延迟 |
| recovery_ops |
视配置而定 |
- |
当前恢复操作数 |
| misplaced_objects |
扩容期间会增加 |
> 10% 且不下降 |
需要迁移的对象数 |
| osd_apply_latency_ms |
< 50ms |
> 100ms |
OSD 写入延迟 |
5.2.3 Prometheus 监控配置
# Ceph 扩容监控告警规则
groups:
- name: ceph_expansion_alerts
rules:
- alert: CephRecoveryTooSlow
expr: |
rate(ceph_pg_recovery_bytes[5m]) < 10485760
and ceph_pg_total - ceph_pg_active > 0
for: 30m
labels:
severity: warning
annotations:
summary: "Ceph 恢复速度过慢"
description: "恢复速度低于 10MB/s,已持续 30 分钟"
- alert: CephOSDLatencyHigh
expr: |
ceph_osd_apply_latency_ms > 100
for: 10m
labels:
severity: warning
annotations:
summary: "OSD {{ $labels.osd }} 延迟过高"
description: "写入延迟 {{ $value }}ms"
- alert: CephExpansionStalled
expr: |
increase(ceph_pg_recovery_bytes[1h]) == 0
and ceph_pg_total - ceph_pg_active > 0
for: 1h
labels:
severity: critical
annotations:
summary: "Ceph 扩容停滞"
description: "过去 1 小时无恢复进度"
5.3 备份与恢复
5.3.1 扩容前检查清单
#!/bin/bash
# 扩容前检查脚本
# 文件名:pre_expansion_check.sh
echo "=== Ceph 扩容前检查 ==="
# 1. 集群健康检查
echo -n "集群健康状态: "
health=$(ceph health 2>/dev/null)
if [ "$health" == "HEALTH_OK" ]; then
echo "✅ OK"
else
echo "⚠️ WARNING: $health"
exit 1
fi
# 2. 检查是否有异常 PG
echo -n "异常 PG 检查: "
stuck=$(ceph pg dump_stuck 2>/dev/null | wc -l)
if [ "$stuck" -eq 0 ]; then
echo "✅ OK"
else
echo "⚠️ WARNING: 有 $stuck 个 stuck PG"
fi
# 3. 检查 OSD 状态
echo -n "OSD 状态检查: "
down=$(ceph osd tree 2>/dev/null | grep -c "down")
if [ "$down" -eq 0 ]; then
echo "✅ OK"
else
echo "⚠️ WARNING: 有 $down 个 down OSD"
fi
# 4. 检查容量
echo -n "容量检查: "
usage=$(ceph df 2>/dev/null | grep "TOTAL" | awk '{print $4}' | tr -d '%')
if [ "$usage" -lt 70 ]; then
echo "✅ OK ($usage%)"
else
echo "⚠️ WARNING: 使用率 $usage%,建议低于 70%"
fi
# 5. 备份 CRUSH map
echo "备份 CRUSH map..."
ceph osd getcrushmap -o /backup/crushmap_$(date +%Y%m%d).bin
crushtool -d /backup/crushmap_$(date +%Y%m%d).bin -o /backup/crushmap_$(date +%Y%m%d).txt
echo "=== 检查完成 ==="
5.3.2 回滚流程
如果扩容出现严重问题,需要回滚:
1. 暂停恢复操作:
ceph osd set norecover
ceph osd set nobackfill
2. 将新 OSD 权重设为 0:
for i in $(ceph osd ls-tree new-host); do
ceph osd crush reweight osd.$i 0
done
3. 移除新 OSD(如果必要):
for i in $(ceph osd ls-tree new-host); do
ceph osd out osd.$i
ceph osd crush remove osd.$i
ceph osd rm osd.$i
ceph auth del osd.$i
done
4. 恢复 CRUSH map(最后手段):
ceph osd setcrushmap -i /backup/crushmap_xxx.bin
六、总结
6.1 技术要点回顾
- ✅ 要点一:扩容前必须确保集群健康,使用率低于 70%,为数据迁移留出空间
- ✅ 要点二:分批次添加 OSD,每批不超过总数的 10-15%,避免一次性触发大规模数据迁移
- ✅ 要点三:使用权重渐进式调整,新 OSD 初始权重设为 0,然后逐步提升到目标值
- ✅ 要点四:全程监控集群状态和业务延迟,准备好紧急止血方案(norecover/nobackfill)
6.2 进阶学习方向
1. CRUSH 算法深入理解
掌握 CRUSH map 的结构和算法原理
- 学习资源:Ceph 官方文档 CRUSH 章节、Sage Weil 的论文
- 实践建议:在测试环境手动编辑 CRUSH map,理解不同规则对数据分布的影响
2. Ceph 性能调优
针对不同负载类型优化 Ceph 配置
- 学习资源:Ceph Performance Tuning Guide
- 实践建议:使用
ceph tell osd.* bench 进行基准测试
3. 大规模 Ceph 运维
万级 OSD 规模的运维经验
- 学习资源:CERN、DigitalOcean 等大规模用户的实践分享
- 实践建议:关注 Ceph User 邮件列表和年度 Cephalocon 会议
6.3 参考资料
- 📚 Ceph 官方文档 - Adding/Removing OSDs - 官方扩容指南
- 📚 Red Hat Ceph Storage Administration Guide - 企业级运维指南
- 📚 Ceph: Designing and Implementing Scalable Storage Systems - O'Reilly 出版的 Ceph 书籍
- 💬 Ceph Users Mailing List - 社区问答
附录
A. 命令速查表
# 集群状态
ceph status # 查看集群状态
ceph health detail # 查看健康详情
ceph osd tree # 查看 OSD 树
ceph osd df tree # 查看 OSD 使用率
# 扩容相关
ceph osd crush reweight osd.X Y # 设置 OSD CRUSH 权重
ceph osd reweight osd.X Y # 设置 OSD 权重(影响 PG 分布)
ceph osd set noout # 防止 OSD 被标记为 out
ceph osd set norecover # 暂停恢复操作
ceph osd set nobackfill # 暂停回填操作
# 监控
ceph progress # 查看操作进度
ceph pg stat # 查看 PG 统计
ceph osd perf # 查看 OSD 性能
B. 配置参数详解
| 参数 |
默认值 |
建议值(扩容期间) |
说明 |
| osd_recovery_max_active |
3 |
1 |
每个 OSD 并发恢复操作数 |
| osd_max_backfills |
1 |
1 |
每个 OSD 并发 backfill 数 |
| osd_recovery_priority |
5 |
1-3 |
恢复优先级(1-63) |
| osd_recovery_sleep_hdd |
0 |
0.1 |
HDD 恢复操作间隔(秒) |
| osd_recovery_max_bytes |
100MB |
30-50MB |
恢复带宽限制 |
C. 术语表
| 术语 |
英文 |
解释 |
| OSD |
Object Storage Daemon |
Ceph 存储守护进程,每个磁盘对应一个 OSD |
| CRUSH |
Controlled Replication Under Scalable Hashing |
Ceph 数据分布算法 |
| PG |
Placement Group |
放置组,数据分片的逻辑单位 |
| Backfill |
Backfill |
数据回填,将数据复制到新位置 |
| Recovery |
Recovery |
数据恢复,修复降级的数据 |
| Rebalancing |
Rebalancing |
数据重平衡,调整数据在 OSD 间的分布 |
💡 提示:本文档基于实际生产环境经验总结,建议在测试环境充分验证后再应用于生产环境。# Ceph 集群平滑扩容实战指南
一、概述
1.1 背景介绍
去年我们的 Ceph 集群从 500TB 扩容到 1.2PB 时,经历了一次"事故级"的扩容体验。原本计划周末完成的扩容,结果拖了整整一周,期间业务延迟飙升 10 倍,差点酿成 P0 故障。这次惨痛经历让我深刻理解了 Ceph 数据重平衡的机制,也总结出一套相对稳妥的扩容方案。
Ceph 是一个分布式存储系统,其核心特性之一是数据的自动重平衡(Rebalancing)。当集群拓扑发生变化(添加/删除 OSD)时,CRUSH 算法会重新计算数据的分布位置,导致大量数据迁移。如果不加以控制,这个过程会消耗大量带宽和 IO 资源,严重影响前端业务。
1.2 技术特点
- CRUSH 算法驱动:Ceph 使用 CRUSH 算法计算数据存放位置,扩容时会触发重新计算,部分数据需要迁移到新节点
- 后台自动执行:数据重平衡由 Ceph 自动执行,默认配置下会尽可能快地完成迁移,不考虑业务影响
- 可控性有限:虽然可以调整重平衡速度,但完全暂停会导致数据分布不均,同样影响性能
- 累积效应明显:一次性添加多个 OSD,数据迁移量会叠加,对集群的冲击成倍增加
1.3 适用场景
- 场景一:生产环境 Ceph 集群容量扩展,需要在不影响业务的前提下完成
- 场景二:硬件升级换代,需要逐步替换旧 OSD 并添加新 OSD
- 场景三:集群性能优化,通过调整 OSD 分布改善数据均衡性
- 场景四:机房迁移或多机房部署,涉及大规模数据重分布
1.4 环境要求
| 组件 |
版本要求 |
说明 |
| Ceph |
Quincy (17.x) 或 Reef (18.x) |
本文基于 Quincy 版本,Pacific 及更早版本部分参数不同 |
| 操作系统 |
Ubuntu 22.04 / Rocky Linux 9 |
需要内核 5.4+ 以获得更好的 BlueStore 性能 |
| 网络 |
10GbE 以上,建议 25GbE |
公网/集群网分离,扩容期间重平衡走集群网 |
| 内存 |
每 OSD 8GB+ |
BlueStore 缓存需要足够内存 |
二、详细步骤
2.1 准备工作
2.1.1 扩容前评估
在动手之前,必须搞清楚几个关键问题:
# 查看当前集群状态
ceph status
ceph health detail
# 检查当前 OSD 数量和分布
ceph osd tree
# 查看当前数据分布情况
ceph osd df tree
# 计算当前集群使用率
ceph df detail
# 检查 PG 状态,确保没有异常
ceph pg stat
ceph pg dump_stuck
关键指标确认:
- ✅ 集群健康状态必须是
HEALTH_OK
- ✅ 没有处于
degraded、recovering、backfilling 状态的 PG
- ✅ 没有处于
down 状态的 OSD
- ✅ 集群使用率低于 70%(留出重平衡缓冲空间)
2.1.2 规划扩容批次
这是最关键的一步。根据我的经验,单批次添加的 OSD 数量不应超过总 OSD 数量的 10-15%。
# 假设当前有 100 个 OSD,计划添加 20 个 OSD
# 建议分 2-3 批次进行:
# 批次1:添加 8 个 OSD
# 批次2:添加 8 个 OSD
# 批次3:添加 4 个 OSD
# 估算数据迁移量
# 假设当前数据量 500TB,100 个 OSD
# 添加 8 个 OSD 后,理论上需要迁移的数据:
# 500TB * (8 / 108) ≈ 37TB
2.1.3 调整重平衡参数(扩容前)
在添加 OSD 之前,先调整重平衡参数,限制数据迁移速度:
# 设置较低的重平衡速度参数
# osd_recovery_max_active:每个 OSD 并发恢复操作数
ceph config set osd osd_recovery_max_active 1
# osd_recovery_max_active_hdd:HDD 专用参数(如果是 HDD)
ceph config set osd osd_recovery_max_active_hdd 1
# osd_recovery_max_active_ssd:SSD 专用参数
ceph config set osd osd_recovery_max_active_ssd 2
# osd_max_backfills:每个 OSD 并发 backfill 数
ceph config set osd osd_max_backfills 1
# osd_recovery_sleep:恢复操作间隔(毫秒),增加此值降低恢复速度
ceph config set osd osd_recovery_sleep_hdd 0.1
ceph config set osd osd_recovery_sleep_ssd 0
# osd_recovery_priority:恢复操作优先级(1-63,数值越小优先级越低)
ceph config set osd osd_recovery_priority 1
2.2 核心配置
2.2.1 设置 OSD 初始权重为 0
这是避免数据风暴的关键技巧。新添加的 OSD 初始权重设为 0,不参与数据分布:
# 添加新 OSD 时使用 --crush-initial-weight=0 参数
# 使用 cephadm 部署时的配置
ceph orch daemon add osd <host>:<device> --crush-initial-weight=0
# 或者在 OSD 添加后立即设置权重为 0
ceph osd crush reweight osd.<id> 0
说明:权重为 0 的 OSD 不会被 CRUSH 算法选中存放数据,这样可以让我们控制数据迁移的节奏。
2.2.2 逐步提升 OSD 权重
添加 OSD 后,逐步提升权重,控制数据迁移量:
# 假设新添加了 osd.100 到 osd.107(共 8 个)
# 目标权重为 1.0(对应 1TB 磁盘)
# 第一轮:权重提升到 0.1
for i in {100..107}; do
ceph osd crush reweight osd.$i 0.1
done
# 等待重平衡完成
watch -n 5 'ceph status | grep -E "recovery|backfill|misplaced"'
# 确认无重平衡活动后,进行第二轮
for i in {100..107}; do
ceph osd crush reweight osd.$i 0.3
done
# 重复上述过程,逐步提升到 0.5 -> 0.7 -> 0.9 -> 1.0
参数说明:
- 权重提升幅度建议不超过 0.2,步子太大会导致瞬间大量数据迁移
- 每轮权重提升后,必须等待重平衡完成再进行下一轮
- 夜间业务低峰期可以适当加大步长,提高效率
2.2.3 使用 noout 标志保护
在扩容期间,设置 noout 标志防止短暂的网络抖动导致 OSD 被标记为 out:
# 设置 noout 标志
ceph osd set noout
# 扩容完成后取消
ceph osd unset noout
# 也可以针对特定 OSD 设置
ceph osd add-noout osd.100
ceph osd rm-noout osd.100
2.3 启动和验证
2.3.1 监控重平衡进度
# 实时监控集群状态
watch -n 2 'ceph status'
# 查看重平衡详情
ceph progress
# 查看 PG 恢复状态
ceph pg stat
ceph pg dump_stuck recovering
# 查看各 OSD 的恢复任务
ceph daemon osd.0 perf dump | grep -E "recovery|backfill"
2.3.2 监控业务影响
# 监控 OSD 延迟
ceph osd perf
# 监控 IOPS 和吞吐量
ceph daemon osd.0 perf dump | jq '.osd.op_r, .osd.op_w'
# 使用 rados bench 测试当前性能(慎用,会增加负载)
# rados bench -p test-pool 60 write --no-cleanup
# 检查慢请求
ceph daemon osd.0 dump_ops_in_flight
ceph daemon osd.0 dump_blocked_ops
三、示例代码和配置
3.1 完整配置示例
3.1.1 扩容前的参数配置
# 文件路径:保存为 ceph_expansion_config.sh
#!/bin/bash
# Ceph 集群扩容前配置脚本
echo "=== 设置重平衡限速参数 ==="
# 降低恢复操作的并发度
ceph config set osd osd_recovery_max_active 1
ceph config set osd osd_recovery_max_active_hdd 1
ceph config set osd osd_recovery_max_active_ssd 2
ceph config set osd osd_max_backfills 1
# 设置恢复操作的优先级和间隔
ceph config set osd osd_recovery_priority 1
ceph config set osd osd_recovery_sleep_hdd 0.1
ceph config set osd osd_recovery_sleep_ssd 0.02
# 限制恢复操作的带宽
ceph config set osd osd_recovery_max_bytes 52428800 # 50MB/s
# 设置 noout 防止误判
ceph osd set noout
echo "=== 当前配置 ==="
ceph config dump | grep -E "recovery|backfill"
echo "=== 集群状态 ==="
ceph status
3.1.2 自动化扩容脚本
#!/bin/bash
# Ceph OSD 权重渐进式调整脚本
# 文件名:gradual_weight_adjust.sh
# 配置参数
OSD_IDS="100 101 102 103 104 105 106 107" # 新添加的 OSD ID 列表
TARGET_WEIGHT=1.0 # 目标权重
STEP=0.2 # 每次提升的权重步长
CHECK_INTERVAL=30 # 检查间隔(秒)
MAX_WAIT_TIME=3600 # 单轮最大等待时间(秒)
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 检查是否有活跃的重平衡
check_rebalance_active() {
local status=$(ceph status 2>/dev/null)
if echo "$status" | grep -qE "recovery|backfill|misplaced|degraded"; then
return 0 # 有活跃重平衡
else
return 1 # 无活跃重平衡
fi
}
# 等待重平衡完成
wait_for_rebalance() {
local waited=0
log "等待重平衡完成..."
while check_rebalance_active; do
if [ $waited -ge $MAX_WAIT_TIME ]; then
log "警告:等待超时,但仍有重平衡活动"
return 1
fi
sleep $CHECK_INTERVAL
waited=$((waited + CHECK_INTERVAL))
# 显示进度
local progress=$(ceph progress json 2>/dev/null | jq -r '.events[0].progress // 0')
log "重平衡进度: ${progress}%, 已等待: ${waited}s"
done
log "重平衡完成"
return 0
}
# 获取当前权重
get_current_weight() {
local osd_id=$1
ceph osd crush tree --format json 2>/dev/null | \
jq -r ".nodes[] | select(.id == ${osd_id}) | .crush_weight"
}
# 主流程
main() {
log "开始渐进式 OSD 权重调整"
log "目标 OSD: $OSD_IDS"
log "目标权重: $TARGET_WEIGHT, 步长: $STEP"
# 计算轮次
local rounds=$(echo "scale=0; $TARGET_WEIGHT / $STEP" | bc)
log "预计需要 $rounds 轮调整"
for round in $(seq 1 $rounds); do
local new_weight=$(echo "scale=1; $STEP * $round" | bc)
log "=== 第 $round 轮:调整权重到 $new_weight ==="
for osd_id in $OSD_IDS; do
local current=$(get_current_weight $osd_id)
log "调整 osd.$osd_id: $current -> $new_weight"
ceph osd crush reweight osd.$osd_id $new_weight
done
# 等待本轮重平衡完成
sleep 10 # 给 Ceph 一点时间开始重平衡
if ! wait_for_rebalance; then
log "警告:第 $round 轮等待超时,继续下一轮"
fi
log "第 $round 轮完成"
echo ""
done
log "=== 所有调整完成 ==="
ceph osd df tree
}
# 执行
main
3.2 实际应用案例
案例一:500TB 扩容到 800TB
场景描述:生产环境 Ceph 集群,原有 60 个 OSD(每个 8TB HDD),需要添加 36 个 OSD,实现从 500TB 到 800TB 的扩容。业务是在线视频点播,对延迟敏感,扩容期间不能影响用户体验。
实现步骤:
1. 扩容前准备
# 检查集群状态
ceph status
# 确认 HEALTH_OK,无异常 PG
# 设置限速参数
ceph config set osd osd_recovery_max_active 1
ceph config set osd osd_max_backfills 1
ceph config set osd osd_recovery_max_bytes 31457280 # 30MB/s
ceph osd set noout
2. 分批添加 OSD
# 第一批:添加 12 个 OSD(osd.60 到 osd.71)
# 初始权重为 0
for i in {60..71}; do
ceph orch daemon add osd node$((i-60)).storage.local:/dev/sdb --crush-initial-weight=0
done
# 渐进式提升权重
for weight in 0.1 0.3 0.5 0.7 0.9 1.0; do
for i in {60..71}; do
ceph osd crush reweight osd.$i $weight
done
echo "权重调整到 $weight,等待重平衡..."
while ceph status | grep -qE "recovery|backfill"; do
sleep 60
done
echo "重平衡完成,继续下一轮"
done
# 等待完全稳定后,进行第二批
# 重复上述过程
运行结果:
扩容过程数据:
- 总耗时:5 天
- 业务延迟影响:P99 延迟从 50ms 上升到 80ms(可接受范围内)
- 数据迁移量:约 240TB
- 每批次迁移耗时:约 40 小时
- 扩容期间无告警,无用户投诉
案例二:紧急扩容(不推荐但有时不得不做)
场景描述:集群使用率已经到了 85%,必须在 48 小时内完成扩容,否则会触发 nearfull 状态。这种情况下需要在风险可控的前提下加快进度。
实现步骤:
1. 评估风险和选择窗口
# 分析业务流量,选择低峰期
# 假设凌晨 2-6 点是最低峰期
# 设置较激进的限速参数
ceph config set osd osd_recovery_max_active 3
ceph config set osd osd_max_backfills 2
ceph config set osd osd_recovery_max_bytes 104857600 # 100MB/s
2. 一次性添加所有 OSD 但分步调权重
# 添加所有 OSD,初始权重 0
ceph orch apply osd --all-available-devices --crush-initial-weight=0
# 低峰期快速提权(大步长)
# 凌晨 2 点
for i in $(ceph osd ls); do
weight=$(ceph osd crush tree --format json | jq -r ".nodes[] | select(.id == $i) | .crush_weight")
if [ "$weight" == "0" ]; then
ceph osd crush reweight osd.$i 0.5
fi
done
# 凌晨 5 点(如果重平衡基本完成)
for i in $(ceph osd ls); do
weight=$(ceph osd crush tree --format json | jq -r ".nodes[] | select(.id == $i) | .crush_weight")
if [ "$weight" == "0.5" ]; then
ceph osd crush reweight osd.$i 1.0
fi
done
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 容量规划
预留扩容缓冲:集群使用率不要超过 70%,留出足够空间应对扩容期间的数据迁移
# 定期检查容量告警
ceph df detail
# 设置告警阈值
ceph config set global mon_osd_full_ratio 0.95
ceph config set global mon_osd_nearfull_ratio 0.85
ceph config set global mon_osd_backfillfull_ratio 0.90
按故障域扩容:
- 新 OSD 应该均匀分布在不同的 host/rack/datacenter
- 避免单个故障域容量过大
- 确保数据副本分布符合预期
4.1.2 网络优化
分离公网和集群网:确保重平衡流量走集群网,不影响客户端访问
# 检查网络配置
ceph config get osd public_network
ceph config get osd cluster_network
# 配置示例
ceph config set global public_network 192.168.1.0/24
ceph config set global cluster_network 192.168.2.0/24
启用巨型帧:减少网络开销
# 在所有存储节点上配置
ip link set eth1 mtu 9000
4.1.3 时间窗口选择
- 业务低峰期操作:权重调整尽量在业务低峰期进行
- 避免关键业务窗口:电商大促、财务结算等关键时期不要扩容
- 分时段调整:白天设置较低的恢复速度,夜间提高速度
# 可以使用 cron 实现分时段调整
# 白天限速(8:00)
0 8 * * * ceph config set osd osd_recovery_max_active 1
# 夜间加速(22:00)
0 22 * * * ceph config set osd osd_recovery_max_active 3
4.2 注意事项
4.2.1 配置注意事项
⚠️ 警告:以下操作可能导致数据丢失或集群不可用,务必谨慎
- 注意事项一:永远不要在集群状态非
HEALTH_OK 时开始扩容
- 注意事项二:不要同时进行多种变更操作(如扩容同时调整 CRUSH 规则)
- 注意事项三:确保新 OSD 的硬件配置与现有 OSD 一致,避免性能不均衡
4.2.2 常见错误
| 错误现象 |
原因分析 |
解决方案 |
| OSD 添加后立即 down |
新 OSD 磁盘或网络问题 |
检查磁盘健康状态、网络连通性、日志 |
| 重平衡速度过慢 |
限速参数设置过于保守 |
在业务允许范围内适当提高恢复参数 |
| 业务延迟飙升 |
重平衡占用过多 IO |
降低恢复参数,考虑暂停重平衡 |
| PG 长时间处于 remapped 状态 |
OSD 权重或 CRUSH 规则问题 |
检查 CRUSH 规则,确认 OSD 权重正确 |
| 扩容后数据不均衡 |
CRUSH 权重未正确设置 |
使用 ceph osd reweight-by-utilization 调整 |
4.2.3 紧急止血
当扩容过程中出现严重问题时,需要紧急止血:
# 暂停所有恢复操作
ceph osd set norecover
ceph osd set nobackfill
# 检查问题后,如果需要继续
ceph osd unset norecover
ceph osd unset nobackfill
# 如果某个 OSD 有问题,可以先将其权重设为 0
ceph osd crush reweight osd.<problem_id> 0
五、故障排查和监控
5.1 故障排查
5.1.1 日志查看
# 查看 OSD 日志
journalctl -u ceph-osd@0 -f
# 查看特定时间段的日志
journalctl -u ceph-osd@0 --since "2024-01-01 10:00:00" --until "2024-01-01 12:00:00"
# 查看 MON 日志(监控 CRUSH 变更)
journalctl -u ceph-mon@mon01 | grep -i crush
# 查看集群事件
ceph log last 100
5.1.2 常见问题排查
问题一:OSD 添加成功但数据迁移不开始
# 诊断命令
ceph osd tree # 确认 OSD 状态为 up+in
ceph osd crush tree # 确认 OSD 在正确的 CRUSH 位置
ceph osd df # 确认权重不为 0
ceph pg dump_stuck # 检查是否有 stuck PG
解决方案:
- 确认 OSD 权重大于 0
- 检查 CRUSH 规则是否将新 OSD 纳入
- 检查是否设置了
norecover/nobackfill 标志
问题二:重平衡过程中 OSD 频繁 flapping
# 诊断命令
ceph health detail
ceph osd dump | grep "last_clean_begin"
dmesg | grep -i "osd\|ceph"
解决方案:
- 检查网络稳定性,是否有丢包
- 检查磁盘是否有 slow ops
- 适当增加
mon_osd_min_down_reporters 和 mon_osd_down_out_interval
问题三:扩容后性能下降明显
- 症状:IOPS 下降 30% 以上,延迟增加
- 排查:检查数据分布是否均衡,是否有热点 OSD
- 解决:使用
ceph osd reweight-by-utilization 调整权重
# 查看 OSD 使用率差异
ceph osd df tree
# 自动调整权重(会模拟执行,需要确认)
ceph osd reweight-by-utilization
ceph osd test-reweight-by-utilization
# 手动调整特定 OSD
ceph osd reweight osd.<id> <weight> # 注意:这是 reweight 不是 crush reweight
5.1.3 深入诊断
# 查看单个 OSD 的详细状态
ceph daemon osd.0 status
# 查看 OSD 的 perf counter
ceph daemon osd.0 perf dump
# 查看 PG 分布
ceph pg dump | awk '/^[0-9]/ {print $1,$15,$16}' | sort -k2 -n
# 查看恢复操作详情
ceph pg dump | grep -E "recovering|backfilling"
5.2 性能监控
5.2.1 关键指标监控
# 实时监控脚本
watch -n 5 'echo "=== 集群状态 ==="
ceph status | head -20
echo ""
echo "=== OSD 延迟 (ms) ==="
ceph osd perf | head -10
echo ""
echo "=== 恢复进度 ==="
ceph progress
echo ""
echo "=== IO 统计 ==="
ceph daemon osd.0 perf dump | jq ".osd | {op_r_latency: .op_r_latency, op_w_latency: .op_w_latency}"'
5.2.2 监控指标说明
| 指标名称 |
正常范围 |
告警阈值 |
说明 |
| op_r_latency |
< 10ms (SSD) / < 50ms (HDD) |
2x 基线 |
读操作延迟 |
| op_w_latency |
< 20ms (SSD) / < 100ms (HDD) |
2x 基线 |
写操作延迟 |
| recovery_ops |
视配置而定 |
- |
当前恢复操作数 |
| misplaced_objects |
扩容期间会增加 |
> 10% 且不下降 |
需要迁移的对象数 |
| osd_apply_latency_ms |
< 50ms |
> 100ms |
OSD 写入延迟 |
5.2.3 Prometheus 监控配置
# Ceph 扩容监控告警规则
groups:
- name: ceph_expansion_alerts
rules:
- alert: CephRecoveryTooSlow
expr: |
rate(ceph_pg_recovery_bytes[5m]) < 10485760
and ceph_pg_total - ceph_pg_active > 0
for: 30m
labels:
severity: warning
annotations:
summary: "Ceph 恢复速度过慢"
description: "恢复速度低于 10MB/s,已持续 30 分钟"
- alert: CephOSDLatencyHigh
expr: |
ceph_osd_apply_latency_ms > 100
for: 10m
labels:
severity: warning
annotations:
summary: "OSD {{ $labels.osd }} 延迟过高"
description: "写入延迟 {{ $value }}ms"
- alert: CephExpansionStalled
expr: |
increase(ceph_pg_recovery_bytes[1h]) == 0
and ceph_pg_total - ceph_pg_active > 0
for: 1h
labels:
severity: critical
annotations:
summary: "Ceph 扩容停滞"
description: "过去 1 小时无恢复进度"
5.3 备份与恢复
5.3.1 扩容前检查清单
#!/bin/bash
# 扩容前检查脚本
# 文件名:pre_expansion_check.sh
echo "=== Ceph 扩容前检查 ==="
# 1. 集群健康检查
echo -n "集群健康状态: "
health=$(ceph health 2>/dev/null)
if [ "$health" == "HEALTH_OK" ]; then
echo "✅ OK"
else
echo "⚠️ WARNING: $health"
exit 1
fi
# 2. 检查是否有异常 PG
echo -n "异常 PG 检查: "
stuck=$(ceph pg dump_stuck 2>/dev/null | wc -l)
if [ "$stuck" -eq 0 ]; then
echo "✅ OK"
else
echo "⚠️ WARNING: 有 $stuck 个 stuck PG"
fi
# 3. 检查 OSD 状态
echo -n "OSD 状态检查: "
down=$(ceph osd tree 2>/dev/null | grep -c "down")
if [ "$down" -eq 0 ]; then
echo "✅ OK"
else
echo "⚠️ WARNING: 有 $down 个 down OSD"
fi
# 4. 检查容量
echo -n "容量检查: "
usage=$(ceph df 2>/dev/null | grep "TOTAL" | awk '{print $4}' | tr -d '%')
if [ "$usage" -lt 70 ]; then
echo "✅ OK ($usage%)"
else
echo "⚠️ WARNING: 使用率 $usage%,建议低于 70%"
fi
# 5. 备份 CRUSH map
echo "备份 CRUSH map..."
ceph osd getcrushmap -o /backup/crushmap_$(date +%Y%m%d).bin
crushtool -d /backup/crushmap_$(date +%Y%m%d).bin -o /backup/crushmap_$(date +%Y%m%d).txt
echo "=== 检查完成 ==="
5.3.2 回滚流程
如果扩容出现严重问题,需要回滚:
1. 暂停恢复操作:
ceph osd set norecover
ceph osd set nobackfill
2. 将新 OSD 权重设为 0:
for i in $(ceph osd ls-tree new-host); do
ceph osd crush reweight osd.$i 0
done
3. 移除新 OSD(如果必要):
for i in $(ceph osd ls-tree new-host); do
ceph osd out osd.$i
ceph osd crush remove osd.$i
ceph osd rm osd.$i
ceph auth del osd.$i
done
4. 恢复 CRUSH map(最后手段):
ceph osd setcrushmap -i /backup/crushmap_xxx.bin
六、总结
6.1 技术要点回顾
- ✅ 要点一:扩容前必须确保集群健康,使用率低于 70%,为数据迁移留出空间
- ✅ 要点二:分批次添加 OSD,每批不超过总数的 10-15%,避免一次性触发大规模数据迁移
- ✅ 要点三:使用权重渐进式调整,新 OSD 初始权重设为 0,然后逐步提升到目标值
- ✅ 要点四:全程监控集群状态和业务延迟,准备好紧急止血方案(norecover/nobackfill)
6.2 进阶学习方向
1. CRUSH 算法深入理解
掌握 CRUSH map 的结构和算法原理
- 学习资源:Ceph 官方文档 CRUSH 章节、Sage Weil 的论文
- 实践建议:在测试环境手动编辑 CRUSH map,理解不同规则对数据分布的影响
2. Ceph 性能调优
针对不同负载类型优化 Ceph 配置
- 学习资源:Ceph Performance Tuning Guide
- 实践建议:使用
ceph tell osd.* bench 进行基准测试
3. 大规模 Ceph 运维
万级 OSD 规模的运维经验
- 学习资源:CERN、DigitalOcean 等大规模用户的实践分享
- 实践建议:关注 Ceph User 邮件列表和年度 Cephalocon 会议
6.3 参考资料
- 📚 Ceph 官方文档 - Adding/Removing OSDs - 官方扩容指南
- 📚 Red Hat Ceph Storage Administration Guide - 企业级运维指南
- 📚 Ceph: Designing and Implementing Scalable Storage Systems - O'Reilly 出版的 Ceph 书籍
- 💬 Ceph Users Mailing List - 社区问答
附录
A. 命令速查表
# 集群状态
ceph status # 查看集群状态
ceph health detail # 查看健康详情
ceph osd tree # 查看 OSD 树
ceph osd df tree # 查看 OSD 使用率
# 扩容相关
ceph osd crush reweight osd.X Y # 设置 OSD CRUSH 权重
ceph osd reweight osd.X Y # 设置 OSD 权重(影响 PG 分布)
ceph osd set noout # 防止 OSD 被标记为 out
ceph osd set norecover # 暂停恢复操作
ceph osd set nobackfill # 暂停回填操作
# 监控
ceph progress # 查看操作进度
ceph pg stat # 查看 PG 统计
ceph osd perf # 查看 OSD 性能
B. 配置参数详解
| 参数 |
默认值 |
建议值(扩容期间) |
说明 |
| osd_recovery_max_active |
3 |
1 |
每个 OSD 并发恢复操作数 |
| osd_max_backfills |
1 |
1 |
每个 OSD 并发 backfill 数 |
| osd_recovery_priority |
5 |
1-3 |
恢复优先级(1-63) |
| osd_recovery_sleep_hdd |
0 |
0.1 |
HDD 恢复操作间隔(秒) |
| osd_recovery_max_bytes |
100MB |
30-50MB |
恢复带宽限制 |
C. 术语表
| 术语 |
英文 |
解释 |
| OSD |
Object Storage Daemon |
Ceph 存储守护进程,每个磁盘对应一个 OSD |
| CRUSH |
Controlled Replication Under Scalable Hashing |
Ceph 数据分布算法 |
| PG |
Placement Group |
放置组,数据分片的逻辑单位 |
| Backfill |
Backfill |
数据回填,将数据复制到新位置 |
| Recovery |
Recovery |
数据恢复,修复降级的数据 |
| Rebalancing |
Rebalancing |
数据重平衡,调整数据在 OSD 间的分布 |
💡 提示:本文档基于实际生产环境经验总结,建议在测试环境充分验证后再应用于生产环境。