今天想在一个集群看下 pg 自动扩缩的情况,结果发现没有任何输出:
1 | ceph osd pool autoscale-status |
1. 问题排查
确认 pg 自动扩缩这个功能已经打开了:
1 | ceph mgr module enable pg_autoscaler |
1 | ceph osd pool get noautoscale |
确认每个池都启用了 pg 自动扩缩功能(省略了不需要的输出):
1 | ceph osd pool ls detail |
所以设置方面是没什么问题的,肯定是被其他东西影响了。
跟踪检查了下 mgr 日志,发现了下面这一段 debug 内容:
1 | docker logs -f `docker ps | grep ceph-mgr | cut -d ' ' -f 1` |
mgr 的 debug 日志,说池 ec 因为重叠的 roots {-1, -2} 而导致无法自动扩展 PG,然后是说池 1、2、3,即所有的池都因为包含重叠的 root 导致跳过了 PG 扩展。这看起来就是问题的主要原因了。
前面 ceph osd pool ls detail
的输出可以看到,我这里有三个池:
device_health_metrics
:Ceph 内建的池。rp
:一个副本池。ec
:一个纠删码池。
我查了一下集群中的 CRUSH 规则:
1 | [ |
从规则信息可以看到,规则 replicated_rule 的 item
为 -1,item_name
为 default。规则 ec 的 item
为 -2,item_name
为 default~ssd。这其实是说这两个规则分别使用设备类(device class) default 和设备类 default~ssd,但因为我这个集群中只有一种设备 ssd,所以这两个规则的 default 和 default~ssd 是等价的,所以出现了 -1 和 -2 这两个不同的 root 就是冲突的。更进一步的理解涉及 CRUSH 算法,这里暂不讨论。
这也就应了日志中的 :
1 | ... [pg_autoscaler WARNING root] pool ec won't scale due to overlapping roots: {-1, -2} |
另外,这个 default~ssd 其实是来自 ec 这个纠删码池的配置,我这里配置名字叫 eck4m2,是一个 EC 4+2 的池。查看一下配置:
1 | ceph osd erasure-code-profile get eck4m2 |
可以看到 default~ssd 其实是字段 crush-root
和 crush-device-class
拼起来的结果。
2. 问题解决
归根结底,导致 CRUSH 根重叠的原因是,多个规则使用同一设备类(配置中的 item_name
),且设置了重叠的 root(配置中的 item
)。正常情况下,应该是这样的:
- 当多个 CRUSH 规则使用同一设备类时,应当有不重叠的 root。
- 不同设备类之间的 root 相互独立,互不影响。
因为我的集群只有一个设备类,所以要保证多个 CRUSH 的 item_name
一样或者推断一样(比如我这里只有 ssd 设备,那么设备类 default 和 default~ssd 是等价的)的前提下,有不重叠的 root。
最简单的解决办法,就是新建一个 ec profile(注意不要指定 crush-device-class
字段,否则又会拼接出 default~*,其他字段按需设置):
1 | osd erasure-code-profile set <name> [<profile>...] [--force] |
然后根据刚新建的 ec profile 创建新的 CRUSH 规则:
1 | osd crush rule create-erasure <name> [<profile>] |
最后给我们出问题的池应用新的 CRUSH 规则,我这里是给池 ec 应用规则 ec-new:
1 | ceph osd pool set <pool_name> crush_rule <crush_rule_name> |
到这里问题就解决了,可以再次看下 ceph osd pool autoscale-status
的输出,符合预期:
1 | ceph osd pool autoscale-status |
至于废弃掉的旧 ec profile 和 CRUSH 规则,删不删的就随意了。
3. 问题复盘
这个问题本质上是 CRUSH 规则中的设备类(Crush device class)设置的不对。
那么为什么不对,经过我的排查,发现使用 Dashboard 创建自定义配置的纠删码池时此问题最高发。原因是在 dashboard 创建自定义配置时,crush-device-class
字段的值默认会被设上(在命令行创建的时候一般不会特意指定这个值):
我们手动给设成 Let Ceph decide 即可不再出现此问题:
其实一开始的时候有搜索到红帽一个解决方案:
https://access.redhat.com/solutions/6987628
但是由于这个页面只有红帽开发者才能看,等我加入红帽开发者的申请通过的时候,我已经搞定了 =。=