归置组是如何使用的?
存储池内的归置组( PG )把对象汇聚在一起,因为跟踪每一个对象的位置及其元数据需要大量计算——即一个拥有数百万对象的系统,不可能在对象这一级追踪位置。
Ceph 客户端会计算某一对象应该位于哪个归置组里,它是这样实现的,先给对象 ID 做哈希操作,然后再根据指定存储池里的 PG 数量、存储池 ID 做一个运算。
PG 映射到 OSD
每个存储池都有很多归置组, CRUSH 动态的把它们映射到 OSD 。 Ceph 客户端要存对象时, CRUSH 将把各对象映射到某个归置组。
把对象映射到归置组在 OSD 和客户端间创建了一个间接层。由于 Ceph 集群必须能增大或缩小、并动态地重均衡。如果让客户端“知道”哪个 OSD 有哪个对象,就会导致客户端和 OSD 紧耦合;相反, CRUSH 算法把对象映射到归置组、然后再把各归置组映射到一或多个 OSD ,这一间接层可以让 Ceph 在 OSD 守护进程和底层设备上线时动态地重均衡。下列图表描述了 CRUSH 如何将对象映射到归置组、再把归置组映射到 OSD 。
计算 PG ID
Ceph 客户端绑定到某监视器时,会索取最新的集群运行图副本,有了此图,客户端就能知道集群内的所有监视器、 OSD 、和元数据服务器。然而它对对象的位置一无所知。
对象位置是计算出来的。
客户端只需输入对象 ID 和存储池,此事简单: Ceph 把数据存在某存储池(如 liverpool )中。当客户端想要存命名对象(如 john 、 paul 、 george 、 ringo 等等)时,它用对象名,一个哈希值、 存储池中的归置组数、存储池名计算归置组。 Ceph 按下列步骤计算 PG ID 。
客户端输入存储池 ID 和对象 ID (如 pool=”liverpool” 和 object-id=”john” );
CRUSH 拿到对象 ID 并哈希它;
CRUSH 用 PG 数(如 58 )对哈希值取模,这就是归置组 ID ;
CRUSH 根据存储池名取得存储池 ID (如liverpool = 4 );
CRUSH 把存储池 ID 加到PG ID(如 4.58 )之前。
计算对象位置远快于查询定位, CRUSH 算法允许客户端计算对象应该存到哪里,并允许客户端连接主 OSD 来存储或检索对象。
(OSDs * 100)
Total PGs = ------------
pool size
其结果汇总后应该接近 2 的幂。汇总并非强制的,如果你想确保所有归置组内的对象数大致相等,最好检查下。
比如,一个配置了 200 个 OSD 且副本数为 3 的集群,你可以这样估算归置组数量:
(200 * 100)
----------- = 6667. Nearest power of 2: 8192
3
当用了多个数据存储池来存储数据时,你得确保均衡每个存储池的归置组数量、且归置组数量分摊到每个 OSD ,这样才能达到较合理的归置组总量,并因此使得每个 OSD 无需耗费过多系统资源或拖慢连接进程就能实现较小变迁。