Ceph放置组(PG)详解

发布于:2025-08-13 ⋅ 阅读:(23) ⋅ 点赞:(0)

Ceph 放置组(PG, Placement Group)

PG(Placement Group)是 Ceph 数据分布的核心逻辑单元,负责将对象(Object)映射到物理存储设备(OSD),同时管理数据冗余、负载均衡和故障恢复。以下是 PG 的全面解析:


1. PG 的核心作用

(1) 数据分布的中间层

  • 对象 → PG → OSD
    • 每个对象通过哈希算法映射到一个 PG。
    • PG 通过 CRUSH 算法映射到一组 OSD(如 3 副本或 EC 分片)。
  • 为什么需要 PG?
    • 直接映射海量对象到 OSD 会导致计算开销过大,PG 作为中间层显著降低 CRUSH 算法的计算复杂度。

(2) 负载均衡与容错

  • 均衡数据分布:PG 分散到不同 OSD,避免热点。
  • 故障恢复单元:OSD 故障时,以 PG 为单位恢复数据。

2. PG 的关键概念

(1) PG 的组成

属性 说明
pg_id 唯一标识符(如 1.2f,表示 Pool 1 的第 2f 个 PG)。
up set 当前负责该 PG 的 OSD 列表(如 [osd.1, osd.5, osd.9])。
acting set 实际存储数据的 OSD 列表(在 OSD 故障时可能与 up set 不同)。
state PG 状态(如 active+cleanrecovering)。

(2) PG 状态详解

状态 含义
active PG 可正常读写。
clean 数据完全同步,无缺失副本。
peering PG 内的 OSD 正在同步元数据。
recovering 正在恢复丢失的数据(如 OSD 故障后重新上线)。
backfilling 新 OSD 加入时,数据正在迁移到该 OSD。
degraded 部分副本不可用(如 OSD 宕机),但仍可读写。
undersized 当前副本数低于配置值(如 size=3 但只有 2 个 OSD 存活)。

3. PG 数量的计算与优化

(1) PG 数量公式

pg_num=OSD总数×100副本数(取最接近的 2 的幂) \text{pg\_num} = \frac{\text{OSD总数} \times 100}{\text{副本数}} \quad \text{(取最接近的 2 的幂)} pg_num=副本数OSD总数×100(取最接近的 2 的幂)

  • 示例
    • 100 个 OSD,3 副本 → (100×100)/3 ≈ 3333 → 取 4096
    • 纠删码池(如 k=4):分母用 k 而非 k+m(如 (100×100)/4=25002048)。

关于纠删码池分母用k还是k+m有所争议,官网公式是
pg_num=OSD总数×100pool size(取最接近的 2 的幂) \text{pg\_num} = \frac{\text{OSD总数} \times 100}{\text{pool size}} \quad \text{(取最接近的 2 的幂)} pg_num=pool sizeOSD总数×100(取最接近的 2 的幂)
而且官方原文是【Here pool size is either the number of replicas for replicated pools or the K+M sum for erasure-coded pools. To retrieve this sum, run the command ceph osd erasure-code-profile get.】这里虽然明确写了pool size=K+M,但是Ceph计算pg_num的源码中明确了pool size的取值是K,代码如下:

// 源码片段(简化)
int pg_num = (osd_count * 100) / ec_profile.k;  // 非 k+m

基于以上内容,本文暂时相信这里是K,由于此时笔者还为搭建集群, 如果您搭建好了集群,可以用如下方法验证

** 验证方法**

(1) 创建测试池
# 创建 EC 池(k=4, m=2)
ceph osd erasure-code-profile set ec42 k=4 m=2
ceph osd pool create ec_test 64 64 erasure ec42
(2) 检查参数
ceph osd pool get ec_test size     # 输出 6 (k+m)
ceph osd pool get ec_test min_size # 输出 4 (k)
(3) 观察 PG 分布
ceph pg dump | grep ^[0-9] | awk '{print $1,$15}' | head
  • 每个 PG 的 acting set 包含 k+m 个 OSD,但只有 k 个数据块需要均衡分布。

(2) 为什么 PG 数量重要?

  • 过少:数据分布不均,某些 OSD 负载过高。
  • 过多:内存开销大(每个 PG 需维护元数据),CRUSH 计算延迟增加。

(3) 自动调整 PG 数量

启用 pg_autoscaler 模块自动优化:

ceph mgr module enable pg_autoscaler
ceph osd pool set <pool-name> pg_autoscale_mode on

4. PG 的数据分布机制

(1) 对象 → PG 映射

  • 计算对象的 PG ID:
    pg_id=hash(object_id) % pg_num \text{pg\_id} = \text{hash(object\_id)} \ \% \ \text{pg\_num} pg_id=hash(object_id) % pg_num
    • 相同 object_id 始终映射到同一 PG。

(2) PG → OSD 映射(CRUSH 算法)

  1. 输入:PG ID、CRUSH Map、Placement Rule。
  2. 输出:一组 OSD(如 [osd.1, osd.5, osd.9])。
  3. 策略
    • 副本池:选择不同故障域的 OSD(如跨主机、机架)。
    • 纠删码池:数据块和校验块分布到不同 OSD。

5. PG 的运维操作

(1) 查看 PG 状态

ceph pg dump | grep <pg_id>       # 查看特定 PG
ceph pg <pg_id> query             # 详细 PG 信息
ceph pg stat                      # 全局 PG 状态

(2) 修复问题 PG

  • 卡住的 PG
    ceph pg force-recovery <pg_id>  # 强制恢复
    ceph pg repair <pg_id>          # 修复不一致
    
  • Unfound 对象
    ceph pg <pg_id> mark_unfound_lost revert  # 放弃丢失数据
    

(3) 调整 PG 分布

ceph osd reweight-by-utilization  # 自动均衡 OSD 负载
ceph osd crush reweight osd.<id> <weight>  # 手动调整 OSD 权重

6. 常见问题与解决方案

Q1: PG 长时间处于 incomplete 状态?

  • 原因:无法找到足够 OSD 存储副本。
  • 解决:检查 OSD 状态(ceph osd tree),确保集群健康。

Q2: 如何减少 PG 数量?

  • 不支持直接减少,需创建新池并迁移数据:
    rados cppool old_pool new_pool
    

Q3: 为什么 PG 的 upacting set 不同?

  • 故障恢复中acting set 包含临时替代的 OSD,直到原 OSD 恢复。

7. 最佳实践

  1. 初始化时合理设置 pg_num,避免后期调整。
  2. 监控 PG 状态ceph -s 检查 active+clean 比例。
  3. 分离热点池:将高 IOPS 池(如 RBD)与冷数据池(如 EC)隔离。
  4. 定期检查 OSD 权重:确保数据分布均衡。

总结

  • PG 是 Ceph 数据管理的逻辑单元,平衡性能与一致性。
  • CRUSH 算法 + PG 实现去中心化分布,无需元数据服务器。
  • 运维关键点:PG 数量、状态监控、故障恢复。

网站公告

今日签到

点亮在社区的每一天
去签到