找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

395

积分

0

好友

37

主题
发表于 昨天 05:31 | 查看: 5| 回复: 0

一、概述

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
  • ✅ 没有处于 degradedrecoveringbackfilling 状态的 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

解决方案:

  1. 确认 OSD 权重大于 0
  2. 检查 CRUSH 规则是否将新 OSD 纳入
  3. 检查是否设置了 norecover/nobackfill 标志

问题二:重平衡过程中 OSD 频繁 flapping

# 诊断命令
ceph health detail
ceph osd dump | grep "last_clean_begin"
dmesg | grep -i "osd\|ceph"

解决方案:

  1. 检查网络稳定性,是否有丢包
  2. 检查磁盘是否有 slow ops
  3. 适当增加 mon_osd_min_down_reportersmon_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
  • ✅ 没有处于 degradedrecoveringbackfilling 状态的 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

解决方案:

  1. 确认 OSD 权重大于 0
  2. 检查 CRUSH 规则是否将新 OSD 纳入
  3. 检查是否设置了 norecover/nobackfill 标志

问题二:重平衡过程中 OSD 频繁 flapping

# 诊断命令
ceph health detail
ceph osd dump | grep "last_clean_begin"
dmesg | grep -i "osd\|ceph"

解决方案:

  1. 检查网络稳定性,是否有丢包
  2. 检查磁盘是否有 slow ops
  3. 适当增加 mon_osd_min_down_reportersmon_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 间的分布

💡 提示:本文档基于实际生产环境经验总结,建议在测试环境充分验证后再应用于生产环境。




上一篇:Python字符串处理:空格去除的3种方法对比与最佳实践
下一篇:Vue2组件通信全面解析:8种传值方案与实战避坑指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-11 00:58 , Processed in 1.006608 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表