数据库集群安装完成后,其数据存储容量是预先规划并确定的。随着时间的推移以及业务量的增加,数据库集群中的可用存储空间不断减少,面临数据存储容量扩充的需求。
传统的在线扩容的流程大致如下。
(1)在集群中加入新的 Datanode Master 节点。由于在创建 Hash 表和复制表时,将表分布的节点写入表定义(pgxc_class),因此新增 Datanode Master 节点后,新建表会使用新增节点,而之前建立的表不会使用新增节点, 从而不会影响表的访问。
(2)对于已经存在的表,调用 alter table 语句,重新分布已有表的数据,对表加锁(AccessExclusiveLock)进行数据重分布,释放表锁,通过新增Datanode Master 节点重新分布数据,现有方案就完成了集群数据扩容。
传统方案存在的问题是,在表的扩容期间,AccessExclusiveLock 锁会阻塞对该表的所有操作,对于大容量表,扩容时间长,会影响集群的可用性。由此, AntDB 提出了hot expasion 扩容方案,将扩容对集群可用性的影响限制在秒(10s) 级别。
1.关键技术
1)HashMap 路由算法
对于分区表,要根据记录的分区字段取值确定该记录所在的数据节点。原有路由算法为:
节点序号 =hash(hashkey)/ 节点数量
该算法存在两个问题:一是记录所在的位置是由分区字段值确定的,如果数据倾斜,无法将数据量多的节点中的数据迁移到数据量少的节点。二是扩容时,为避免数据全部重新分布,通常采用将 n 节点扩容到 2n 节点的方法。
系统中原有 2 个数据节点 DB1 和 DB2,扩容为 4 个数据节点 DB1、DB1’、DB2、DB2’,如图 3-23 所示。
由于 Hash 算法基于节点数目取模,无法做到 DB1 数据不动,仅增加 DB2’
节点,对 DB2 扩容,如图 3-24 所示。
为克服以上问题,hot expasion 扩容方案采用 HashMap 路由算法。首先,将整个集群的数据划分为 1024(可设定)的 slot。对分片 key 字段Hash 后,除 1024 取模,可以得到一个对应的 slotid。示意代码如下:
其次,建立 slotid 到物理节点的映射表,表示 slotid 的数据存放在 nodeid 节点,映射表(SlotNodeMap)维护数据的映射和每个 slot 的状态,包含以下字段:
●slotid:slot序号。
●nodeid:节点序号。
●status: slot的状态,包括在线( online)、迁移( move)、清除(clean)。
最后,数据路由时,通过 slotid 从映射表中找到对应的节点。示意代码如下:
2)数据热备份与增量数据同步
扩容节点需要复制被扩容节点的完整数据。数据复制包括基础数据复制和增量数据复制两个部分。采用 checkpoint 和 xlog 同步技术完成复制,不会影响被扩容数据节点对外提供服务。首先,在被扩容节点做 checkpoint;然后, 直接热拷贝数据到扩容节点做基线数据备份,之后,启动扩容节点,建立到被扩容节点的流复制,从 checkpoint 的 redo_lsn 位置开始回放 xlog 日志,做增量数据同步。AntDB 的 basebackup 工具已实现以上功能,hot expasion 直接使用basebackup 工具完成数据复制。
基于 AntDB 的逻辑复制,可以实现一个数据节点中的 slotid 数据热迁移到另外一个数据节点,以平衡数据的分布。
3)重复数据处理
将 1 个数据节点扩容为 2 个数据节点的过程中,1 条记录会存储在 2 个数据节点。重复数据的存在,需要增加记录的可见性处理和冗余数据删除。对于不包含分区键信息的 SQL 语句,数据节点需要根据 HashMap 路由算法计算该记录的 slotid,并判断该 slotid 是否属于本节点,该步骤称为 slot 可见性处理。对每条记录进行 Hash 算法,会占用较多 CPU 资源,应仅在必须时才进行 slot 可见性处理。路由切换完成后,被扩容节点和扩容节点都包含冗余数据。将冗余数据删除后,空间才能够被再次利用,实现数据扩容。冗余数据的删除不应影响正常的数据访问,并能够根据集群负载调整删除进度。
hot expasion 将扩容操作分为数据同步、路由切换、数据清理三个阶段, 节点的状态包括 online、move、clean、expended,具体如下:
●online:节点处于非扩容状态。
●move:被扩容节点状态,表示该节点正在向扩容节点同步数据。
●clean:被扩容节点已加入集群,节点包含冗余数据。
一次扩容中被扩容节点状态变化为 online → move → clean → online,扩容节点状态变化为expended → clean → online。
扩容具体流程见“z. 扩容示例”。
hot expasion 仅在数据清理阶段(节点状态为 clean)启用 slot 可见性处理, 在非扩容和扩容的同步数据阶段不启用 slot 可见性处理,将该操作对集群性能的影响降至最低。
节点进入 clean 状态后,自动启动清除进程。该进程首先统计当前节点的Hash 表,并依次对每个 Hash 表进行清除处理,删除非本节点数据。根据系统负载控制删除进度,当所有 Hash 表清除完成后,节点进入 clean 状态。清除处理使用普通的 delete from 语句处理流程,只在数据可见性判断时,返回不属于本节点的记录,从而删除非本节点数据,保留本节点数据。此清除方法,不需要改动 vacuum 和事务处理流程,对系统的影响最小。