`

一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案

 
阅读更多

原文:http://blog.csdn.net/bluishglc/article/details/7970268

一般来说,“理想”的扩容方案应该努力满足以下几个要求:

  1.  最好不迁移数据 (无论如何,数据迁移都是一个让团队压力山大的问题)
  2. 允许根据硬件资源自由规划扩容规模和节点存储负载
  3. 能均匀的分布数据读写,避免“热点”问题
  4. 保证对已经达到存储上限的节点不再写入数据

 

目前,能够避免数据迁移的优秀方案并不多,相对可行的有两种,一种是维护一张记录数据ID和目标Shard对应关系的映射表,写入时,数据都写入新扩容的Shard,同时将ID和目标节点写入映射表,读取时,先查映射表,找到目标Shard后再执行查询。该方案简单有效,但是读写数据都需要访问两次数据库,且映射表本身也极易成为性能瓶颈。为此系统不得不引入分布式缓存来缓存映射表数据,但是这样也无法避免在写入时访问两次数据库,同时大量映射数据对缓存资源的消耗以及专门为此而引入分布式缓存的代价都是需要权衡的问题。另一种方案来自淘宝综合业务平台团队,它利用对2的倍数取余具有向前兼容的特性(如对4取余得1的数对2取余也是1)来分配数据,避免了行级别的数据迁移,但是依然需要进行表级别的迁移,同时对扩容规模和分表数量都有限制。总得来说,这些方案都不是十分的理想,多多少少都存在一些缺点,这也从一个侧面反映出了Sharding扩容的难度。

 

取长补短,兼容并包——一种理想的Sharding扩容方案

 

如前文所述,Sharding扩容与系统采用的路由规则密切相关:基于散列的路由能均匀地分布数据,但却需要数据迁移,同时也无法避免对达到上限的节点不再写入新数据;基于增量区间的路由天然不存在数据迁移和向某一节点无上限写入数据的问题,但却存在“热点”困扰。我们设计方案的初衷就是希望能结合两种路由规则的优势,摒弃各自的劣势,创造出一种接近“理想”状态的扩容方式,而这种方式简单概括起来就是:全局按增量区间分布数据,使用增量扩容,无数据迁移,局部使用散列方式分散数据读写,解决“热点”问题,同时对Sharding拓扑结构进行建模,使用一致的路由算法,扩容时只需追加节点数据,不再修改散列逻辑代码。

 

原理

 

首先,作为方案的基石,为了能使系统感知到Shard并基于Shard的分布进行路由计算,我们需要建立一个可以描述Sharding拓扑结构的编程模型。按照一般的切分原则,一个单一的数据库会首先进行垂直切分,垂直切分只是将关系密切的表划分在一起,我们把这样分出的一组表称为一个Partition。 接下来,如果Partition里的表数据量很大且增速迅猛,就再进行水平切分,水平切分会将一张表的数据按增量区间或散列方式分散到多个Shard上存储。在我们的方案里,我们使用增量区间与散列相结合的方式,全局上,数据按增量区间分布,但是每个增量区间并不是按照某个Shard的存储规模划分的,而是根据一组Shard的存储总量来确定的,我们把这样的一组Shard称为一个ShardGroup,局部上,也就是一个ShardGroup内,记录会再按散列方式均匀分布到组内各Shard上。这样,一条数据的路由会先根据其ID所处的区间确定ShardGroup,然后再通过散列命中ShardGroup内的某个目标Shard。在每次扩容时,我们会引入一组新的Shard,组成一个新的ShardGroup,为其分配增量区间并标记为“可写入”,同时将原有ShardGroup标记为“不可写入”,于是新生数据就会写入新的ShardGroup,旧有数据不需要迁移。同时,在ShardGroup内部各Shard之间使用散列方式分布数据读写,进而又避免了“热点”问题。最后,在Shard内部,当单表数据达到一定上限时,表的读写性能就开始大幅下滑,但是整个数据库并没有达到存储和负载的上限,为了充分发挥服务器的性能,我们通常会新建多张结构一样的表,并在新表上继续写入数据,我们把这样的表称为“分段表”(Fragment Table)。不过,引入分段表后所有的SQL在执行前都需要根据ID将其中的表名替换成真正的分段表名,这无疑增加了实现Sharding的难度,如果系统再使用了某种ORM框架,那么替换起来可能会更加困难。目前很多数据库提供一种与分段表类似的“分区”机制,但没有分段表的副作用,团队可以根据系统的实现情况在分段表和分区机制中灵活选择。总之,基于上述切分原理,我们将得到如下Sharding拓扑结构的领域模型:

 

图1. Sharding拓扑结构领域模型

 

 

在这个模型中,有几个细节需要注意:ShardGroup的writable属性用于标识该ShardGroup是否可以写入数据,一个Partition在任何时候只能有一个ShardGroup是可写的,这个ShardGroup往往是最近一次扩容引入的;startId和endId属性用于标识该ShardGroup的ID增量区间;Shard的hashValue属性用于标识该Shard节点接受哪些散列值的数据;FragmentTable的startId和endId是用于标识该分段表储存数据的ID区间。

 

确立上述模型后,我们需要通过配置文件或是在数据库中建立与之对应的表来存储节点元数据,这样,整个存储系统的拓扑结构就可以被持久化起来,系统启动时就能从配置文件或数据库中加载出当前的Sharding拓扑结构进行路由计算了(如果结点规模并不大可以使用配置文件,如果节点规模非常大,需要建立相关表结构存储这些结点元数据。从最新的Oracle发布的《面向大规模可伸缩网站基础设施的MySQL参考架构》白皮书一文的“超大型系统架构参考”章节给出的架构图中我们可以看到一种名为:Shard Catalog的专用服务器,这个其实是保存结点配置信息的数据库),扩容时只需要向对应的文件或表中加入相关的节点信息重启系统即可,不需要修改任何路由逻辑代码。

 

示例

 

让我们通过示例来了解这套方案是如何工作的。

 

阶段一:初始上线

 

假设某系统初始上线,规划为某表提供4000W条记录的存储能力,若单表存储上限为1000W条,单库存储上限为2000W条,共需2个Shard,每个Shard包含两个分段表,ShardGroup增量区间为0-4000W,按2取余分散到2个Shard上,具体规划方案如下:

图2. 初始4000W存储规模的规划方案

 

与之相适应,Sharding拓扑结构的元数据如下:

图3. 对应Sharding元数据

 

 

阶段二:系统扩容

 

经过一段时间的运行,当原表总数据逼近4000W条上限时,系统就需要扩容了。为了演示方案的灵活性,我们假设现在有三台服务器Shard2、Shard3、Shard4,其性能和存储能力表现依次为Shard2<Shard3<Shard4,我们安排Shard2储存1000W条记录,Shard3储存2000W条记录,Shard4储存3000W条记录,这样,该表的总存储能力将由扩容前的4000W条提升到10000W条,以下是详细的规划方案:

图4. 二次扩容6000W存储规模的规划方案

 

相应拓扑结构表数据下:

 

图5. 对应Sharding元数据

 

 

从这个扩容案例中我们可以看出该方案允许根据硬件情况进行灵活规划,对扩容规模和节点数量没有硬性规定,是一种非常自由的扩容方案。

 

增强

 

接下来让我们讨论一个高级话题:对“再生”存储空间的利用。对于大多数系统来说,历史数据较为稳定,被更新或是删除的概率并不高,反映到数据库上就是历史Shard的数据量基本保持恒定,但也不排除某些系统其数据有同等的删除概率,甚至是越老的数据被删除的可能性越大,这样反映到数据库上就是历史Shard随着时间的推移,数据量会持续下降,在经历了一段时间后,节点就会腾出很大一部分存储空间,我们把这样的存储空间叫“再生”存储空间,如何有效利用再生存储空间是这些系统在设计扩容方案时需要特别考虑的。回到我们的方案,实际上我们只需要在现有基础上进行一个简单的升级就可以实现对再生存储空间的利用,升级的关键就是将过去ShardGroup和FragmentTable的单一的ID区间提升为多重ID区间。为此我们把ShardGroup和FragmentTable的ID区间属性抽离出来,分别用ShardGroupInterval和FragmentTableIdInterval表示,并和它们保持一对多关系。

 



 

图6. 增强后的Sharding拓扑结构领域模型

 

 

让我们还是通过一个示例来了解升级后的方案是如何工作的。

 

阶段三:不扩容,重复利用再生存储空间

 

假设系统又经过一段时间的运行之后,二次扩容的6000W条存储空间即将耗尽,但是由于系统自身的特点,早期的很多数据被删除,Shard0和Shard1又各自腾出了一半的存储空间,于是ShardGroup0总计有2000W条的存储空间可以重新利用。为此,我们重新将ShardGroup0标记为writable=true,并给它追加一段ID区间:10000W-12000W,进而得到如下规划方案:



 

图7. 重复利用2000W再生存储空间的规划方案

 

 

相应拓扑结构的元数据如下:



 

图8. 对应Sharding元数据

 

小结

 

这套方案综合利用了增量区间和散列两种路由方式的优势,避免了数据迁移和“热点”问题,同时,它对Sharding拓扑结构建模,使用了一致的路由算法,从而避免了扩容时修改路由代码,是一种理想的Sharding扩容方案。

  • 大小: 105.5 KB
  • 大小: 195.8 KB
  • 大小: 212.7 KB
分享到:
评论

相关推荐

    数据库秒级平滑扩容架构方案

    该平滑扩容方案的核心优势在于无需停机即可实现数据库的秒级扩容,并且能够有效地减少数据迁移的工作量,提高扩容过程的安全性和稳定性。通过成倍扩容而非直接迁移数据,不仅减少了运维人员的工作压力,还大大提升了...

    sharding jdbc 基于java代码的配置.zip

    Sharding-JDBC是一款轻量级的Java框架,它旨在解决大数据量下的数据库分库分表问题,无需修改数据库和业务代码,只需要通过配置或者注解就能实现数据的分布式处理。本压缩包“sharding jdbc 基于java代码的配置.zip...

    shardingJdbc功能代码

    ShardingJDBC是阿里巴巴开源的一款轻量级Java框架,它为数据库分片提供了一种解决方案。这个框架的主要目的是解决在大数据场景下,由于单表数据量过大导致的性能瓶颈问题。ShardingJDBC可以在不改变业务代码的情况下...

    数据库之间进行数据迁移代码实例

    数据库之间的数据迁移是IT行业中常见的任务,特别是在系统升级、数据整合或者备份恢复等场景下。本文将详细探讨如何使用JDBC(Java Database Connectivity)技术来实现这一目标,涉及的关键知识点包括数据库连接、...

    MongoDB Sharding 机制分析

    MongoDB Sharding 机制是 MongoDB 中的一种机制,用于将数据水平切分到不同的物理节点,以解决单机性能极限的问题。Sharding 可以利用上更多的硬件资源来解决单机性能极限的问题,并减小每个索引的体积,提高索引...

    springboot整合sharding-jdbc完整代码

    SpringBoot整合Sharding-JDBC是将Sharding-JDBC这一分布式数据库中间件与SpringBoot框架结合,以实现数据分片、读写分离等高级数据库管理功能。这个完整的代码示例覆盖了Sharding-JDBC的主要技术点,使开发者可以...

    如何实现Geo数据的数据 partition 和数据 sharding解决方案(亲测可用).md

    如何实现Geo数据的数据 partition 和数据 sharding解决方案(亲测可用).md

    分布式数据库-MySQL Sharding1

    在实践中, MySQL Sharding1 需要考虑数据库复制、扩容问题、动态数据迁移问题等问题。例如,在大型互联网公司内部,数据库复制可能会出现延迟问题,扩容时需要重新划分数据,动态数据迁移需要总控节点整体协调等。 ...

    Sharding JDBC 实现数据分片 - 技术分享.pdf

    为了解决这些问题,ShardingJDBC提供了一种在应用层实现数据库分片的解决方案,从而将数据分散存储在多个数据库中。 ShardingJDBC的核心概念包括逻辑表、真实表、数据节点、数据分片、分片键、分片算法和分片策略。...

    sharding-jdbc分布式数据库培训方案

    分布式数据库是一种将原本集中存储在一台或少数几台设备上的数据分散存储到多个相互连接的节点上,以提高存储容量和并发处理能力的数据库解决方案。Sharding-JDBC 是一种流行的分布式数据库中间件,它旨在解决大数据...

    分库分表,多数据源的切换

    用户无需修改现有的业务代码,只需在配置中指定分片规则,Sharding-JDBC就会在运行时自动处理数据的分片和路由。其主要特点包括: 1. **轻量级**: Sharding-JDBC作为JDBC驱动,以jar包形式存在,无需额外部署和依赖...

    应对sharding-jdbc结合mybatis实现分库分表功能 分表的联合查询采用将mysql的数据同步到elasticsearch进行筛选

    1. **Sharding-JDBC**:Sharding-JDBC提供了一种透明化的数据库分片解决方案,它作为一个JDBC的驱动,使得应用程序无须修改代码即可使用分片功能。主要特性包括水平分库、水平分表、读写分离和分布式事务等。 2. **...

    Sharding-JDBC使用案例-分库分表

    Sharding-JDBC是由阿里巴巴开源的轻量级Java框架,它定位为数据库中间件,提供了一种无需修改现有应用代码就能实现数据库分库分表的能力。Sharding-JDBC完全基于JDBC标准,可以理解为一个增强版的数据库驱动,它工作...

    基于mybatis插件实现轻量级分库分表方案-亿级数据mysql存储解决方案-mybatis-sharding.zip

    MyBatis-Sharding 是一种基于 MyBatis 的轻量级分库分表解决方案,它可以帮助开发者有效地解决亿级数据量下的 MySQL 存储问题。下面将详细介绍 MyBatis-Sharding 的核心概念、实现原理以及如何在实际项目中进行应用...

    simple-sharding, A simple database shard middleware.zip

    GitHub社区是开源软件的聚集地,这里不仅包含了simple-sharding的最新版本,还有丰富的文档、示例代码和用户交流,是学习和解决问题的好去处。在下载的simple-sharding-master文件中,你可以找到项目的源代码、测试...

    Sharding JDBC PPT 分享

    Sharding JDBC是一款开源的轻量级Java框架,它提供了一种分库分表的解决方案,用于解决大规模数据集下的数据库的性能问题。Sharding JDBC具有易于使用,无需额外依赖和强依赖数据库的特点。它允许开发人员对JDBC进行...

    一步步搭建基于RedHat 7 Oracle 12c Sharding

    与Oracle Real Application Clusters(Oracle RAC)不同,Sharding依赖于一种定义良好的数据模型和数据分布策略,如一致性散列、范围、列表或它们的组合。数据访问主要依赖于分片键,常见的分片键示例包括customer_...

    Java开发案例-springboot-33-整合sharding-jdbc和多数据源-源代码+文档.rar

    Java开发案例-springboot-33-整合sharding-jdbc和多数据源-源代码+文档.rar Java开发案例-springboot-33-整合sharding-jdbc和多数据源-源代码+文档.rar Java开发案例-springboot-33-整合sharding-jdbc和多数据源-源...

    sharding-jdbc数据分片

    "sharding-jdbc数据分片"是Java领域中一种解决大数据量查询效率问题的解决方案。在当今大数据时代,单表数据量过大往往会导致数据库查询效率降低,影响整个系统的响应速度。sharding-jdbc作为一款轻量级的数据分片...

    sharding-jdbc-mybatis.zip

    Sharding-JDBC是阿里巴巴开源的分布式数据库中间件,它提供了一种轻量级的数据库分片解决方案,可以在不修改现有应用代码和数据库表结构的情况下,实现数据库的水平扩展。本实例以"sharding-jdbc-mybatis.zip"为例,...

Global site tag (gtag.js) - Google Analytics