基于 rook 部署 Ceph

文章目录

引言

有位朋友(下文简称小明)的集群 OSD 数据分布很不均匀,最多的 OSD 已经被使用了 90%,而最少的才用了 40%,这种现象的原因基本上可以确定为 PG 总数设置少了,再加上经常有朋友会问及到每个 Pool 的 PG 数该怎么设置,我这里就说下 PG 对数据分布的影响。

因为怎么做官网的pg 计算器已经讲得很明确了,我主要想介绍下为什么要这么做。

这里我完全重搭建出了小明的集群环境,需要他提供几个参考值:

  • ceph osd tree : 用于重建 CRUSH 树,确定 OSD 权重。
  • ceph df:查看集群数据总数。
  • ceph osd pool ls detail,查看每个 pool 的 PG 数。
  • ceph -v: 同样的 Ceph 版本。

简单概述下小明的集群的状态:三主机,每个主机上 13 个 OSD,每个 OSD 权重为1.08989,三副本,三个 PG 数均为 512 的 pool,数据量分别为 102GB, 11940GB, 3454GB, 9.2.1的版本的 Ceph。

我用手头的三个虚拟机,每个虚拟机建立了 13 个目录,用来建 OSD,配置文件里添加了两个配置osd crush update on start = false, osd journal size = 128,用于建完 OSD 后,将 OSD 手动添加至 CRUSH 中,并保证权重和小明的 OSD 权重一样,又因为只是试验用,就把 journal 大小设置很小,主要是盘太多了。

在所有 OSD 完成prepare+activate正常启动后,创建三个 Bucket(host),并将所有的 OSD 添加至对应的 Host 下面,形如:ceph osd crush add osd.0 1.08989 host=ceph-1。添加两个 pool,并将这三个 pool 的 PG 都设置为 512,环境准备完毕。给个截图看得清楚点(对的,OSD 编号本来就不连续,我是按照原样的顺序重建的):
Alt text

查看数据分布

我从磨磨的博客里找了个统计 PG 分布的脚本,列出了这个集群的 PG 分布,如下图:

Alt text

简单说下这个图的意义:

  • pool: 0 1 2:表示 pool 的编号。
  • osd.0 23 20 18: 表示osd.0上有 23 个pool 0的 PG,20 个pool 1的 PG,18 个pool 2的 PG。

这里着重关注下osd.46osd.41上的 PG 数:
Alt text

osd.41 : 22-17-9
osd.46: 23-33-34

集群三个 pool 的数据分布为: 102GB, 11940GB, 3454GB

这里我们假定(实际上也是),每个 pool 里面的 PG 的数据量是相同的,那么这三个 pool 的 PG 数据量平均为:

  • pool 0: 102GB/512 = 0.2GB
  • pool 1: 11940GB/512 = 23.32GB
  • pool 2: 3454GB/512 = 6.75GB

那么这里很快可以计算出这两个 OSD 上的数据量:

  • osd.41: 220.2 + 1723.32 + 9*6.75 = 461.59GB (实际 456G)
  • osd.46: 230.2 + 3323.32 + 34*6.75 = 1003.66GB (实际 994G)

这里再给出小明集群磁盘实际使用率,和我这里估算出来的值基本一样,不信可以再找个 OSD 算算:
Alt text

信息量

整个实验过程,其实包含了很多有用的结论,这里我先罗列下:

  • 只需要提供开篇的几个参考值,搭建出来的集群的 PG 分布就是完全一样的,因为CRUSH(PG)=>OSD set,CRUSH 计算 PG 分布需要知道 OSD 的权重,CRUSH 的树状结构,pool_id+pg_num,只要这些值一样,计算出的结果也一样,简单点说就是克隆出来一个一模一样的集群,只需要几个参考值。
  • 对于同一个池内的 PG,它们的数据量是几乎相等的,这也是有理论依据的,因为HASH(obj) % PG_NUM => PG_ID,这在我的大话 CRUSH 一文中也有介绍,对于几百万个对象,求余得到的 PG_ID 是很均匀的,所以 PG 内的数据量是相等的。
  • 对于不同的 pool 的 PG,分布的数据不一定相等,因为每个 pool 的数据量不一定相等,比如小明的数据量分布我可以很容易猜测到他使用了openstack+ceph的架构,第一个 pool 为rbd,没有保存生产数据,二三两个 pool 的数据比例为11940:3454 = 3.45:1,很明显第二个 pool 用于保存虚拟机,第三个用于保存镜像。这种近似4:1的数据量的结构一般都是openstack+ceph的架构。而每个 PG 的数据量是由pool_data/pg_num求得的。
  • 从集群搭建好 PG 数设置好之后,我们就可以预估某个 OSD 会在数据量达到一定值的时候被塞满了,我们只需要每个 pool 的数据总量即可估算,这里我想表达的是,既然这是一个可预见的问题,我们就应该在集群设置之初解决这个问题。

正确设置 PG 的姿势

首先要定几个规则:

  • 每个 OSD 上的 PG 总数应该尽量相等,且在 100 左右。
  • 每个 pool 的 PG 数应该为 2 的 n 次方。
  • 每个 PG(所有 pool)上的数据应该尽量相等。

主要问题在第三点,由上面的数据可以知道,openstack 的两个 pool 的每个 PG 的平均数据量并不相等:23.32GB 和 6.75GB,造成不相等的原因是,这两个 pool 里面保存的数据量总数不相等(通常为 3:1~5:1),而他们的 PG 数却是相等的,所以,如果把他们的 PG 数设置为 4:1 的话,总数除以 PG 数得到的均值应该就基本上相等了。

所以这里,一个非常非常非常重要的结论就是,应该按照集群的所有 pool 的数据量的比例来设置每个 pool 的 PG 数!

而这个比例通常不好估计,Ceph 官网给我们提供了一个计算公式,给出了常见的生产配比:

比如 openstack 结构的给出了 8:1 的比例,因为volumes池会随业务持续增长,而images池可能在上传完镜像后就不再变化,所以这里的8:1的比例应该是考虑到长远的业务增长造成的volumes池数据不断增长,我们平时看到的3:1->5:1说明业务还有增长空间~~:
Alt text

亦或 RGW 结构的,对.rgw.buckets数据桶给了较大的 PG 数:
Alt text

如果我们有 30 个 OSD,跑三副本的话,要保证每个 OSD 上有 100 个 PG 的话,那么一共会有30 (OSD) * 100 (PG/OSD) = 3000 PG ,再除以三副本的 3,就是 1000 个不同的 PG,如果使用8:1的结构的话,我们可以分别设为1024128的 PG 数。 主要方法是让最大的 pool 向 1000 靠近,取最接近于 2 的 n 次方的值,这里取 1024,再加上八分之一的 128,最终结果会导致每个 OSD 上的 PG 稍微大于 100,不过这没有关系,即使到了两百都可以接受。

对于小明的例子,共有 69 个 OSD,每个 OSD 上有 100 个 PG 的话,共有69 * 100 / 3 = 2300个 PG,按照八比一来分,大的 pool 我们取 2048,小的取 256,一共 2304,正好极其接近 2300,是一个很理想的值。

再取个比较难分的情况,比如共有 100 个 OSD,那么共有 3333 个 PG,还是八比一,这里我们选择往上取 PG 值,对于大 pool,我们取 4096,而不是 2048,小 pool 取 512,这样会使得每个 OSD 平均分到了 138 个 PG,大一点,没有关系的,但是一定不要比 100 小很多,那样会导致 OSD 的 PG 最大最小的比例较大。

主要方法就是求出这个集群总共有多少 PG,然后让数据最大的池的 PG 数向这个数靠近往上取 2 的 n 次方,结果大一点没关系,最好每个 OSD 平均 100PG 以上,取到了两百也没有关系,就是不能小。

还有个叫rbd的系统默认生成的池,这个池如果没有用到的话,直接删掉就好了。

这时候回过来看下小明的 PG 分布,剔除rbd池的 PG,实际上osd.41上只有17+9=26个 PG,而osd.46上却有33+34=67个 PG,因为rbd池基本不放数据,所以可以忽视掉对数据分布的影响,就像 RGW 的 PG 分布除了数据池很大外其他 pool 的 PG 都很小的原因。很明显,数据的分布不均是由于这两个 OSD 上的 PG 数比例较大导致的。

解决方法

说了这么多,小明到底应该怎么做呢?首先,要铭记于心的一个结论是:pg_num只能大不能小,很不幸的是,据我所知,小明同学已经把三个 pool 的 pg_num 都设置为了 1024,如果时间可以倒流的话,我会建议他将volumes池设置为 2048,images池设置为 512,因为不能再小了,既然已经都设到了 1024,那么就再把volumes池的 PG 设到 2048 吧,rbd又不想删又不能减小,那就丢那吧,一个空的 pool,不论 PG 多少,都不会对 OSD 数据分布有影响,起决定作用的是数据最多的那个 pool,所以对于volumes池,一定要将 PG 增大到使得每个 OSD 的 PG(这里的 PG 可以说是不包含 rbd 的,仅包含 volumes 的)平均分布 100 左右。

还有一个缓解办法:手动调整 OSD weight,削峰填谷。对于即将满的 OSD,降低它的权重,让它把数据迁移到别的盘上去,但是对于小明这里的情况,需要削的峰太多了,因为 100±20 的峰和 50±20 的峰是不一样的,如果是 100 的话 80:120=2:3 的比例,如果是 50 的话就是 30:70 的比例了,PG 的比例会最终导致展现为数据分布的比例。所以,并不是很建议去使用这种缓解方法。

现在,我们删去rbd池,将volumes设到 2048,看下 PG 分布:
Alt text
前面的为volumes池的,最大误差为-20% ~ + 28%, 比之前的-59.6% ~ +52.3%要缩小很多,平均每个 OSD 上 89 个volumes池的 PG,因为此时两个 pool 的 PG 比例为 4:1,并且实际数据比例也约为 4:1,所以,每个 OSD 上的 PG 总数比例就是最终 OSD 上的数据比例,最小是 85 个,最大是 137 个,所以对于一个 1.1T 的磁盘,最大的存储到 1T 时,最小的才使用到85/137=0.62T, 不过这要比之前的 0.4T 要好很多了。对于 137 这种峰,我们可以削掉。

总结

这篇文章并没有说明在 OSD 即将满时该怎么处理,而是解释了为什么 PG 的分布不均会导致 OSD 的数据分布不均,重点需要明确的观念是,每个 pool 的 PG 数量应该根据这个 pool 实际的保存数据比例来定,最终使得每个 OSD 的平均 PG 在一百左右,在构建完集群后,最好检测一下集群的 PG 分布,提前将几个峰值削去,而不是等到数据真正堆满了再去削,那时候的数据迁移很容易导致集群垮掉,尽量使得每个 OSD 的 PG 分布在±20%以下。

这篇文章都是个人使用经验,文中给出的参数仅供参考,为的是讲述原理,看看就好。

参考链接

PG 如何影响数据分布