Gpexpand是Greenplum数据库的扩容工具,可以为集群增加新节点从而可以存储更多的数据,提供更高的计算能力。Greenplum 5及之前,集群扩容需要停机增加新节点,然后对表数据做重分布。因为集群大小已经改变,所以重分布之前要先将所有哈希分布表改成随机分布,然后再按照新的集群大小重新计算哈希值并重新分布。
所以,旧的扩容技术存在如下几个问题:
1. 需要停机,集群无法在扩容期间提供服务。
2. 数据重分布过程集群性能差。随机分布表因为不能确定数据分布规律,无法对查询做优化。
3. 虽然表的重分布可以并行进行,但是扩容过程中因为额外记录了每个表的更新状态,在对表做完重分布后要更新状态表。Greenplum 6版本之前表的更新操作只能串行。所以对大量小表做并行重分布的时候会因为状态表更新的串行化产生瓶颈。
全新设计的gpexpand支持在线扩容,同时对数据重分布过程做了优化,提高了并发度。整个扩容分为两个阶段:
1. 在线增加新节点
2. 数据重分布
如何在线增加新节点
Greenplum通过catalog表gp_segment_configuration维护集群节点信息。所以在线增加节点并不复杂,只要更新这个系统表即可:首先以master数据库目录为模板创建新的子节点,然后更新gp_segment_configuration表。新节点没有用户数据,只有catalog数据,这些数据在master节点上都有。
因为是在线扩容,这里有几个问题:
1. 新节点加入后,哈希分布的数据表还是按照旧集群的大小进行哈希分布。对这样的表怎么处理
·正在运行的事务
·新事务
2. 扩容过程中,catalog更改操作(建表,删表,改表)如何处理
问题 1
为了解决这个问题,我们在catalog表gp_distribution_policy里引入了一个新的属性,numsegments。它描述了该表分布在哪些节点上,n表示分布在前n个节点上。同时优化了执行查询的工作进程的数量管理策略,可以指定在哪些节点上启动执行查询工作进程。所以,即使集群添加了新节点,但是未数据重分布的表仍然只分布数据在集群的旧节点上,并且分布策略不变。所以,无论是正在运行的事务,还是新事务,如果numsegments没有改变,则查询执行进程依然只运行在集群的旧节点上,新节点上没有工作进程。
对于新创建的表,则会获取最新集群大小,应用到所有节点上,numsegments值与最新集群大小相同。对该表执行的DML操作,也会应用到所有节点上。
问题 2
扩容期间如果catalog发生变化,则会导致不一致:catalog的变化只应用到了老节点,和新节点上的catalog数据不一致。
为了保证扩容期间catalog的一致性,Greenplum 6引入了catalog锁,在增加新节点阶段,防止对catalog执行修改操作。新节点加入到集群后,该catalog锁被释放。通常添加新节点操作比较快,所以对catalog操作的影响不大。
对于只存在于master上catalog表,如gp_segment_configuration、pg_statistic等,新加入的数据节点会做适当的清理。
数据重分布
表的重分布过程就是将表的数据从旧的集群节点,重新分布到新的集群节点上。重分布后更新numsegments,之后的所有事务会按照新的分布来处理了。在重分布过程中会对表加ACCESS_EXCLUSIVE_LOCK锁,所有对表的操作都会被阻塞。完成某张表的数据重分布后,操作该表的SQL将被调度到集群的所有新旧节点上执行。
重分布的优化
哈希分布计算方法虽然简单,但是在重分布的过程中,由于集群大小发生了变化,需要按照新的集群节点数目重新计算哈希,数据几乎要完全重新分布,移动数据量巨大,导致重分布过程效率较低。假设原来有N个节点,每个节点上分布1/N的数据,扩容后M个节点,每个节点上分布1/M的数据。理想的情况是,每个旧节点移动出1/N - 1/M的数据到新节点上,从而整体移动量是N(1/N - 1/M) = 1 - N/M。
Greenplum 6采用了一种叫做Jump Consistent Hash的一致性哈希算法。
该算法有如下特点:
1. 均匀性:通过概率做到均匀分布。
2. 稳定性:在相同集群大小下,同一个Tuple每次计算结果相同。
3. 单调性:扩容过程中,旧节点之间没有数据迁移。
4. 高效性:对于集群大小为N的时候,时间复杂度为Log(N)。
更多算法细节请参考链接。https://arxiv.org/pdf/1406.2294.pdf
重分布的并行化
在Greenplum 5上,HEAP表的更新删除操作是最高级别的锁,相当于完全是串行化。做数据重分布的过程中,要在一张HEAP表中记录数据库中每个表的重分布状态,所以在做数据重分布的过程中,虽然做了并行化,但是更新状态表的时候仍然是串行的。即使更新状态表的操作很短暂,对于大量小表的并行重分布依然会成为瓶颈。在Greenplum 6里,因为增加了分布式死锁检测,所以更新删除表的锁级别已降低,支持并发更新删除操作。对于大量小表做并行重分布性能提升明显。
重分布期间对查询性能的影响
重分布过程中,不可避免的会存在某些表已经重分布完毕、某些表还未做重分布。对于处于相同分布状态的表,在分布列上做JOIN查询,不需要做数据重分布;否则,需要进行数据重分布。
FAQ
1. 如何控制哈希分布算法
通过GUC gp_use_legacy_hashops 可以控制,默认是Jump Hash算法。
2. 扩容过程中新旧节点的catalog是一致的吗
catalog始终是一致的,新节点上即使还没有数据,但是catalog也是存在的。
3. 扩容过程中对于其他查询的影响
因为是在线扩容,期间不会中断正在运行的所有查询,只是在增加新节点的时候因为要锁catalog,所以在此期间不支持DDL,加完新节点立即释放catalog锁。
在数据重分布的时候因为加了最高级别的锁,对正在重分布的表的访问会阻塞。