GoldenDB 数据库分片与重分布技术详解

GoldenDB数据库支持多种分片和在线重分布策略,实现不停机数据迁移和性能提升。

原文标题:数据库系列之GoldenDB数据库分片和重分布

原文作者:牧羊人的方向

冷月清谈:

GoldenDB 是一款分布式数据库,其数据分片技术是实现横向扩展和提升性能的关键。GoldenDB 支持多种分片规则,包括 Hash 分片、Range 分片、List 分片、复制表和多级分片,以适应不同的应用场景。

Hash 分片采用一致性 Hash 算法,可最大程度减少节点变化带来的数据迁移。Range 分片按数据范围划分,适用于时间或 ID 分区,但可能出现数据冷热不均。List 分片根据枚举值划分,适用于分片键值较少且固定的场景。复制表将数据副本保留在所有数据节点,适用于读多写少的场景。多级分片则通过多维属性精确控制数据分片。

GoldenDB 的分片路由机制能够根据分片规则将 SQL 语句路由到对应的分片节点。插入操作时,DBProxy 解析 SQL 并根据分片规则将数据插入到目标分片。查询操作时,DBProxy 将查询语句下发到所有相关分片节点,并将结果汇总返回给客户端。

GoldenDB 支持在线重分布,可实现不停机的数据迁移和重新均衡。重分布策略包括增量迭代式、Hash 流式和 Range 策略优化。增量迭代式适用于各种场景,Hash 流式针对 Hash 分片横向扩容进行了优化,Range 策略则针对 Range 分片进行了优化。在线重分布通过创建临时表、迁移数据、同步增量更新、切换表名等步骤完成,对业务影响较小。

怜星夜思:

1、在实际应用中,如何选择合适的 GoldenDB 数据分片策略?
2、GoldenDB 的 Hash 流式重分布是如何保证数据一致性的?
3、相比其他分布式数据库,GoldenDB 的分片和重分布机制有哪些优势?

原文内容

数据分片是分布式数据库横向扩展的基础,本文主要整理了GoldenDB的数据库分片技术以及数据重分布实现的过程,加深对分片和重分布技术的理解。

1、数据分片规则
数据的切分(sharding)根据切分规则的类型,可以分为垂直切分和水平切分两种模式:
  • 垂直切分是按照不同的表切分到不同的数据库中,适用于业务系统之间耦合度低、业务逻辑清晰的系统

  • 水平切分是根据表中数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库上,对应用来说更为复杂

数据分片是将数据库横向扩展到多个物理节点的分布式技术,具有以下特性:
  • 无限扩展:数据分片水平切分扩展到多个物理节点,理论上支持无限扩展

  • 性能提升:数据分片以后单个数据节点上上的数据集变小,数据库查询的压力变小、查询更快,性能更好;同时水平切分以后查询可以并发执行,提升了系统的吞吐量

  • 高可用:部分分片节点宕机只会影响该部分分片的服务,不会影响整个系统的可用性

在GoldenDB中支持的分片规则和使用场景如下:

以下部分将介绍GoldenDB的几种分片方法:

1.1 Hash分片
1.1.1 普通hash算法
Hash分片的算法就是对分片键的值进行hash(取模)计算,将计算后的key值映射到不同的服务器上,这样的好处是能将海量的数据均匀的打散在不同的数据节点上。但是普通的hash算法在节点扩容时候,需要对所有的数据进行重新打散,存在大量的数据搬迁。

1.1.2 一致性hash算法

一致性Hash算法最早是解决分布式cache提出的,它将整个hash值空间组织成一个虚拟的圆环,根据节点名称的Hash值将服务器节点放置在这个Hash环上,然后根据数据的Key值计算得到其Hash值,接着在Hash环上顺时针查找距离这个Key值的Hash值最近的服务器节点,完成Key到服务器的映射查找。

如下图所示,当增加新的节点的时候,只有在圆上增加服务器的逆时针的第一台服务器上的主键会受到影响。这种算法解决了普通余数Hash算法伸缩性差的问题,可以保证在上线、下线服务器的情况下尽量有多的请求命中原来路由到的服务器。

  • GoldenDB中的hash算法

GoldenDB中使用的是一致性hash算法,它可以尽可能减少节点数变化引起的数据迁移。
  1. 对分片键计算hash值,该hash值会落到0~N的封闭圆环中

  2. 按照分片数量M将hash值均分为M段(M<<N),确定每个分段的值范围

  3. 将落入同一个分段的hash值划分在同一个分片上

  4. 当增加数据节点时候,会使用到hash流式重分布策略,将其它分片的hash值搬动到新增的节点,使得数据均匀分布

  • Hash分片的语法如下:

Create table t1(a int,b int) distributed by hash(a)(g1,g2,g3);
1.2 Range分片
Range分片是按照数据范围分片,常用于按照时间分区或者ID分区来切分,比如按照不同日月的数据分散到不同的库中。Range分片优点在于集群扩容时候只需要添加节点即可,不需要对分片数据进行迁移;同时对于范围查找时,可以通过分片数据快速查询,有效避免跨分片的查询问题。Range分片也有很明显的问题就是出现冷热数据,以及热点数据集中在单个数据节点上出现性能瓶颈。

  • GoldenDB中range分区示例:

Create table t1(a bigint,b char(6)) distributed by range(a)
(g1 values less than (1000),g2 values less than (2000),g3 values less than maxvalues);
1.3 List分片

List分片是根据不同的枚举值将数据分布在不同的分片上,比如分片键为银行法人,将不同的法人部署在单独的分片上。List分片适合分片键数据较少且固定的场景,但是不同枚举值的数据分布可能出现不均衡的问题。

  • GoldenDB中List分片示例:

Create table t1(a varchar(4),b char(6)) distributed by list(a)
(g1 values in(CN),g2 values in (HK));
1.4 复制表

复制表是在数据节点保留全量的数据副本,有多节点复制表和单节点复制表,通常用于表的数据读多写少变化不大的场景,比如参数表。复制表的好处是将公共访问表存放在本地数据节点,可以减少跨节点的表数据访问和分布式事务开销,提升SQL的性能。

  • GoldenDB中复制表示例:

Create table t1(a varchar(4),b char(6)) distributed by duplicate(g1,g2,g3);
1.5 多级分片

多级分片是通过多维属性对数据分片进行精确控制,通常是通过多个字段进行多层次分片,比如通过法人字段进行一级分片,再按照客户类型字段进行二级分片。

  • GoldenDB中多级分片示例:

Create table t1(a int,b int,c int) distributed by 
case c when 1 then case when b<100 then subdistributed by hash(a) (g1);
else subdistributed by hash(a) (g2);
end case;
when 2 then subdistributed by hash(a) (g3);
else subdistributed by hash(a) (g4);
end case;
1.6 GoldenDB中分区
当表在横向切分后,单节点的表数据依然很大,可以考虑进行纵向分区,将节点上的分片数据进一步进行切分。这样做的好处是比如一些流水表按照时间进行分区,历史档需要定期清理的时候直接drop历史分区即可;同时业务访问表数据的时候可以减少读取的表数据量,快速定位数据提升性能。

  • GoldenDB中分片+分区示例:

Create table t1(a int,b int,c int) partition by range (c)
(partition p1 values less than (20210101), partition p2 values less than (20210201),
partition p3 values less than (20210301), partition p4 values less than (20210401))
distributed by hash (a) (g1,g2);
2、分片路由

2.1 表分片DDL过程
GoldenDB中表分片的DDL会在每个DB数据节点中执行并保存一份完整的DDL信息,整个过程如下:
  1. DBProxy接收到DDL信息后,会通知MDS更新元数据信息,并持久化保存到RDB中

  2. DBProxy将DDL语句下推到每个数据节点分别执行

  3. DBProxy本地内存和数据节点中会保存一份全量的表结构信息

  4. DDL执行过程中如果出错,会通知MDS将表状态禁用,需要手动解锁;表禁用后业务访问会出错

  5. RDB中的DDL信息会定期同步到DBProxy计算节点和DB数据节点

  6. 应用访问时会优先从本地读取DDL信息

2.2 表分片的插入过程
GoldenDB中分片表的插入过程如下:
  1. DBProxy接收到SQL信息后,从MDS获取表的分片信息并解析SQL

  2. DBProxy根据分片规则将SQL语句下发到不同的DB分片节点

  3. DB分片节点执行insert语句,并返回执行结果给计算节点DBProxy

根据路由规则可以看到,相同的表名在不同的DB数据节点执行的是不同的SQL语句。

2.3 表分片的查询过程
GoldenDB中分片表的查询过程如下:
  1. DBProxy接收到SQL信息后,从MDS获取表的分片信息并解析SQL

  2. DBProxy根据分片规则将查询语句下发到不同的DB分片节点

  3. DB分片节点执行SQL查询语句,并返回结果集给计算节点DBProxy进行汇总,再返回给客户端

注:对于不带分片键的查询,会将DB数据节点的查询结果汇总到计算节点,当数据量很大时会出现计算节点OOM情况。

3、在线重分布
3.1 数据重分布策略
GoldenDB支持动态的数据重分布,将数据高效均匀的分布在数据节点上,可实现在线重分布,对业务影响小。重分布过程通过在OMM管理界面以管理任务的形式运行,执行、暂停、继续取消以及异常情况下的重试等,全程可视化控制。同时,数据重分布根据不同的场景有不同的策略,常见的有:增量迭代式数据重分布、HASH策略流式重分布以及RANGE策略重分布优化。

3.1.1 增量迭代式数据重分布
增量迭代式数据重分布是一种通用策略,适合所有的数据重分布场景,比如:
  • 分片策略的变更,由hash变为range,复制表变为分片表等

  • 表分片键的变更,由A列调整为B列

  • 分片策略不变,数据节点横向扩容的场景

增量迭代式数据重分布过程如下图所示:

实现数据重分布策略的基本策略是针对重分布的表,建立一个与原表字段结构相同但是分发策略为新的分发策略的新表,然后将重分布的数据节点上数据导出并导入到新表,最后将新表和旧表的表名切换,总的过程如下:
  1. 按照扩容后的分发策略创建临时表

  2. 导出需要重分布的数据节点的数据,并导入到临时表

  3. 通过binlog数据追平导数期间增量更新的数据到临时表

  4. 将当前表锁住(此时应用不能更新表),并通过binlog追平增量更新数据

  5. 数据校验完毕后,将临时表和新表切换表名,解锁并对外提供服务

  6. 删除旧表的数据

数据重分布过程中需要注意:
  • 锁表和切换表名的过程中,影响应用的写操作

  • 重分布过程中临时表需要额外的存储空间,重分布操作前需要保证存储空间充足

3.1.2 Hash策略流式重分布
Hash策略流式重分布是对通用重分布策略的优化,适用于分片键信息不变,仅进行Hash分片策略横向扩容的场景。
  • 系统中默认包含2048*128个HASH桶,新增数据节点的过程中会并行的从现有的每个分片节点迁移部分数据到新增分片上,确保所有分片数据平均

  • 整个数据迁移的过程是在现有分片数据上动态操作,对磁盘空间没有额外的要求

  • 同步更新MDS和DB节点中表的分片信息

Hash策略流式重分布还有几个细节问题尚待明确:
  • 分片数据从现有分片移动到新增分片的方法,直接导出再load进去?

  • 数据移动的过程中,应用访问到的数据的节点信息和移动后的数据信息不一致该如何处理?

  • 现有分片数据移动到新增分片的算法,即哪些数据会搬到新的分片节点

  • Hash桶数量是有限的,是否会出现Hash值重复的情况?

3.2 重分布任务

3.2.1 创建重分布任务
重分布任务通过OMM管理平台创建,主要分为三步:
  1. 解析重分布任务:MDS对重分布任务进行检查,解析出新的重分布策略,并根据表的老旧分发规则解析出本次重分布涉及哪些分片

  2. 分解重分布步骤并保存重分布任务:MDS会把重分布任务分解为执行步骤,并保存到元数据RDB中

  3. 创建临时表:MDS向各DB分片发起创建临时表的请求,临时表的命名规则为原表名_时间戳

重分布上述三个步骤其中一个失败,整个重分布任务即为失败。同时需要注意的是一张表同时只能有两个重分布任务并行执行,并且重分布的表必须有主键,因为在增量同步过程中读取binlog解析增量更新的数据,再根据主键更新到临时表中。

3.2.2 线下阶段(全量部分)
数据重分布线下阶段分为全量部分和增量部分,只有完成全量部分后才能进行增量部分操作。全量部分是对整个表进行全量的备份和全量恢复到临时表中,主要包括四个步骤:
  1. 全量备份:使用mysqldump进行全量数据备份

  2. 全量恢复:全量恢复是将备份文件根据新的分发策略切分为多个文件传输到其它DB数据节点,并恢复到临时表中

  3. 全量校验:进行全量数据校验,如果数据出现不一致,需重头发起重分布任务

  4. 创建索引:数据校验完成后会通过DBProxy为临时表创建索引

在数据重分布过程中,MDS会有一个定时器定时检测上述步骤的执行情况,并同步更新保存到RDB中。如果某一步执行失败,会重试该步骤,如果出现数据不一致MDS会重头开始执行任务。重做之前会清理垃圾数据,包括导出的数据文件、拆分的数据文件以及表中已经导入的数据等。

3.2.3 线下阶段(增量部分)
数据重分布线下阶段的增量部分是对全量恢复数据期间的binlog解析回放的过程,通过多次追加binlog直到已经基本追平增量数据为止。

3.2.4 线上阶段
数据重分布线上阶段是对表写禁止,同时完成全部增量的binlog数据追加,并切换临时表和原表的表名。主要分为以下步骤:
  1. 表写禁止,此时业务只能查询,不能增删改操作

  2. 追加全部的binlog数据

  3. 增量校验数据的一致性,如果不一致则需要重新开始重分布任务

  4. 数据校验完成后切换表名

  5. 恢复表的写访问,对外提供服务

  6. 清理旧表的数据

至此,GoldenDB分片和数据重分布过程到此结束,其实在线数据重分布的过程和DB2的在线重组过程在实现机制上非常相似。

参考资料

  1. https://www.cnblogs.com/lpfuture/p/5796398.html

  2. https://cloud.tencent.com/developer/article/1763380

  3. GoldenDB数据库分片和重分布技术介绍

针对“GoldenDB 的 Hash 流式重分布是如何保证数据一致性的?”这个问题,个人觉得,在数据迁移的过程中,可能会采用类似两阶段提交的机制,或者其他分布式事务的处理方式。保证在数据搬迁到新的节点后,原节点上的数据才会被删除,并且在搬迁过程中,对数据的读写操作都会被严格控制,以确保数据的一致性。

关于hash流式重分布的数据一致性,我想到一个可能的方案:GoldenDB可能使用了类似版本号或时间戳的机制,对每个数据块进行标记。在迁移过程中,新节点会记录接收到的数据块的版本号,并与原节点进行比对,确保数据是最新的。

“相比其他分布式数据库,GoldenDB 的分片和重分布机制有哪些优势?”,文章中提到了GoldenDB在线重分布对业务影响小,以及Hash策略流式重分布对磁盘空间没有额外要求等优势。个人认为,GoldenDB 的优势可能还在于其支持多种分片策略,以及可视化的重分布管理界面,方便用户操作和监控。

选择分片策略需要结合具体业务场景和数据特点。比如,如果数据量巨大且需要均匀分布,Hash 分片是不错的选择;如果需要按时间范围查询,Range 分片更合适;如果分片键值较少且固定,可以选择 List 分片。

关于“GoldenDB 的 Hash 流式重分布是如何保证数据一致性的?”这个问题,文中提到了GoldenDB使用一致性hash算法进行数据分片,并通过hash流式重分布策略进行数据迁移,但并没有详细解释数据一致性是如何保证的。我猜测,GoldenDB应该采用了一些机制,例如分布式事务或数据同步机制,来确保在数据迁移过程中不会出现数据丢失或不一致的情况。

除了文章提到的几种分片方式外,还可以考虑组合使用,例如先按 Hash 分片再按 Range 分区,以应对更复杂的场景。

实际操作中,可以先进行小规模测试,比较不同分片策略的性能和资源消耗,再选择最优方案。

关于 GoldenDB 的优势,可以从扩展性、性能、可用性和易用性等方面进行比较。比如,GoldenDB 的无限扩展特性、在线重分布机制和可视化管理界面,都是其相比其他分布式数据库的优势。

我觉得GoldenDB的优势之一在于其在线重分布的效率。文章中提到了增量迭代式重分布策略,通过binlog追平增量数据,可以减少数据迁移的时间,从而降低对业务的影响。