ceph健康检查non-power-of-two pg_num警告

小蕊 发表于: 2025-11-17   最后更新时间: 2025-11-17 10:18:49   33 游览

我进行日常的ceph健康检查的时候,发现报non-power-of-two pg_num警告,如下:

# ceph -s
  cluster:
    id:     52eabf04-b7ba-11ef-8287-bba5b8705822
    health: HEALTH_WARN
            1 pool(s) have non-power-of-two pg_num

  services:
    mon: 1 daemons, quorum ww209 (age 4M)
    mgr: ww209.jkkdaw(active, since 8w), standbys: ww209.bduyjm
    mds: 1/1 daemons up
    osd: 6 osds: 6 up (since 8w), 6 in (since 8w)
    rgw: 2 daemons active (1 hosts, 1 zones)

  data:
    volumes: 1/1 healthy
    pools:   16 pools, 182 pgs
    objects: 27.43k objects, 117 GiB
    usage:   118 GiB used, 13 TiB / 13 TiB avail
    pgs:     182 active+clean

请问我该怎么解决?

发表于 2025-11-17

有 1 个 pool 的 PG 数不是 2 的幂(例如 300、500 这种),在 Ceph 中 不推荐,可能导致分布不均。

通过以下命令查看:

ceph osd pool ls detail | grep pg_num

PG 推荐值:

  • 对副本池:每个 pool 的 PG 数取值一般:128、256、512、1024……
  • 对 EC 池:PG 可以不是 2 的幂,但 Ceph 还是推荐 power-of-two

修复:

ceph osd pool set <poolname> pg_num 256
ceph osd pool set <poolname> pgp_num 256

详细解释

PG 到 OSD 的映射是通过哈希(hash)和一致性映射计算出来的,Ceph 对 PG 的编号是按位(二进制位)运算优化的。如果 PG 数不是 2 的幂,PG 的哈希空间无法平均划分,从而导致某些 PG 映射到更多 OSD,某些更少,引起数据倾斜(PG 不均衡)。

为什么要 2 的幂?

因为 二进制世界里最容易等分的就是 2 的幂

1)PG 映射本质是取哈希值的前几位

Ceph 用 CRUSH + 哈希把对象分配到 PG。

过程简化如下:

object -> hash -> % pg_num -> pg_id

注意关键:

  • % pg_num(取模操作)决定对象落在哪个 PG
  • 如果 pg_num = 2^n,则 % 操作相当于 取哈希的低 n 位(二进制)

例:

pg_num = 256 = 2^8
=> object_hash % 256 = 取 hash 的最低 8

这样可以做到:

  • 哈希空间平均切成 256 份
  • 每一份大小一致
  • 每一份对应一个 PG
  • 完全均匀

因为哈希空间天然在二进制上是均匀的。

2)如果 pg_num 不是 2 的幂,就不能整齐切分哈希空间

例如:

pg_num = 300

哈希空间不能平均分成 300 份:

  • 哈希空间是 2^k 大小(比如 2^32)
  • 300 不是能整整分割这个空间的数
  • %300 后的结果并不均匀 → 会造成偏差

举例:

hash % 300

哈希空间范围:0 ~ 2^32-1
而 2^32 除以 300 会留下余数:

2^32 % 300 ≠ 0

这意味着:

  • 一些 PG 会覆盖更多哈希范围
  • 一些 PG 覆盖更少
  • PG 的对象数量不均
  • 所属的 OSD 负载开始倾斜

最终导致:OSD 空间、IO、PG 数量都不平衡。

3)CRUSH 映射也因为 PG 分布不均而无法完全平衡

CRUSH 的目标是:

  • PG 在 OSD 上均匀分布
  • 尽可能保证副本在不同机架、主机、盘上分开

但 CRUSH 的前提是:

PG 自己必须是均匀的。

如果 PG 数内部已经倾斜(因为不是 2 的幂),那么:

  • 一些 OSD 会被分到更多 PG
  • 有的 OSD 负载更大
  • 有的更空
  • 数据迁移时也会不均匀

尤其OSD 数少时(比如你只有 6 个 OSD)这个不均匀放大特别明显

4)举个超级直观的例子(最容易理解)

假设:

  • 你有哈希空间大小 1024(2^10)
  • 你把它分成 10 份(pg_num = 10)

1024 / 10 = 102 余 4

所以:

  • 有 4 个 PG 得到 103 单位空间
  • 其他 PG 得到 102 单位空间

看似差不大,但 Ceph 一个 PG 可能对应几十 GB 数据。

这个小差异会导致 OSD 最终负载明显不同。

如果使用:

pg_num = 8 (2^3)

则:

1024 / 8 = 128(整除)

每个 PG 完全一样 → 完美均匀。

5)真实案例(Ceph 官方报告)

官方统计表明:

  • pg_num 使用非 2 的幂,会出现 5%~30% 的数据倾斜
  • OSD 数越少,倾斜越严重
  • 后期扩容/缩容时倾斜更明显

所以直接在 health 警告里要求修复。

6)为什么 Ceph 允许不是 2 的幂?

历史原因 + 某些算法可以容忍,但最终都建议:

powers of 2

尤其你这种 6 OSD 的小集群,影响更大。

总结(最简精华)

PG 是从哈希空间切分出来的,而哈希空间天然是 2^n 的二进制结构。
用 2 的幂作为 PG 数可以完美等分哈希空间,数据分布才会均匀。
如果 PG 不为 2 的幂,则哈希空间无法整除,PG 分布必然不均匀,导致 OSD 空间、IO 倾斜。

你的答案

查看ceph相关的其他问题或提一个您自己的问题