Ceph放置组(PG)详解
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+clean 、recovering )。 |
(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=2500
→2048
)。
- 100 个 OSD,3 副本 →
关于纠删码池分母用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 算法)
- 输入:PG ID、CRUSH Map、Placement Rule。
- 输出:一组 OSD(如
[osd.1, osd.5, osd.9]
)。 - 策略:
- 副本池:选择不同故障域的 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 的 up
和 acting
set 不同?
- 故障恢复中:
acting set
包含临时替代的 OSD,直到原 OSD 恢复。
7. 最佳实践
- 初始化时合理设置
pg_num
,避免后期调整。 - 监控 PG 状态:
ceph -s
检查active+clean
比例。 - 分离热点池:将高 IOPS 池(如 RBD)与冷数据池(如 EC)隔离。
- 定期检查 OSD 权重:确保数据分布均衡。
总结
- PG 是 Ceph 数据管理的逻辑单元,平衡性能与一致性。
- CRUSH 算法 + PG 实现去中心化分布,无需元数据服务器。
- 运维关键点:PG 数量、状态监控、故障恢复。