作者 姑胥
PolarDB-X作为一款云原生分布式关系型数据库[6] 支持通过拆分规则将一张逻辑表的数据分布在多个数据节点中。同时 也支持变更拆分规则 将数据进行重新分布[9]。数据重新分布 Repartition 的能力是分布式数据库的核心能力之一。当业务规模扩大时 它可以将数据分布到更多的节点 以达到水平扩展 ScaleOut 的目的。当业务规则剧烈变化时 它也可以将数据以新的拆分规则分布 从而提高查询的性能 更好地适应新的业务规则。下图展示如何将一张单表 通过一条简单的DDL语句online地变更为一个分库分表。
其实早在分布式数据库中间件大行其道的年代 开发人员就尝试过各种方式来解决数据Repartition的问题。但是无一例外 这些方案都非常复杂和危险 开发人员通常只能在半夜流量低峰期做Repartition 前前后后需要准备好详细的设计、论证、回滚方案。并且基于分布式的特点 在新老数据切换的那一段时间 几乎总是得在数据一致性和可用性之间做一个痛苦的选择。所以很多方案会有一个停写阶段或数据比对阶段 或两者皆有。
PolarDB-X充分论证了分布式数据库Repartition的各项技术细节后 能够做到Repartition过程中数据强一致、高可用、对业务透明、一条简单DDL语句搞定。
本文讨论的主要是表级别的数据Repartition。比如 将一张拆分表的数据按照新的规则重新分布到不同的数据节点。但是重新分布的过程需要时间 这段时间内又会有新的增量数据进入系统。当所有的数据都重新分布完成后 要将新老数据进行切换 最后停止双写并删掉所有的老数据。仔细研究上述过程的细节后 可以将其概括为这3个关键子问题 后续我们将按照这3个子问题评估各个实现方案
一个传统的Repartition流程大概是这样的
但是如果我们仔细推敲一下 发现很多步骤根本就没办法保障数据一致性
除了数据一致性问题外 依然存在很多繁琐但依然十分重要的问题
PolarDB-X 是一款存储与计算分离的分布式数据库 所以在架构中会分为计算节点 CN 和存储节点 DN 以及一个元数据库 GMS 。CN负责SQL的parse、optimize、execute DN负责数据存储 GMS负责存储元数据。为了性能考虑 每个CN节点都会缓存一份元数据。
在分布式的增量数据双写场景中 双写的2端经常会分布在不同的DN节点中 所以自然地单机事务无法使用。而前文已经论证过 XA事务、binlog同步、触发器都无法保证双写的2端数据强一致。PolarDB-X使用了内置的基于TSO的分布式事务[7] 感兴趣的同学可以点击直达文章 实现增量数据同步 从而保证了Repartition过程中 任意时刻读流量切换的数据的强一致性。
值得注意的是 如果一行数据的拆分列的值被修改了 那这行数据可能会路由到另一个数据节点[1]。所以这时候执行的其实是 原数据节点的delete操作 新数据节点的insert操作。在Repartition过程中 因为前后的拆分规则不同 所以一行数据的update操作 可能会演变成4个数据节点参与的分布式事务 如果有全局二级索引会更多 。PolarDB-X会处理好所有这些工作 用户无需任何感知 可将PolarDB-X视为一个单机数据库操作。
在存量数据同步时 PolarDB-X会分段进行同步。每一段同步过程中 PolarDB-X会在TSO事务中 先尝试获取源端数据的S锁 然后再写入目标端。如果目标段已经有相同数据 则表明增量双写阶段已经将这些数据同步过了 忽略即可。
分布式事务与单机事务一样 会产生死锁。当存量同步而给原表某段数据加S锁时 如果业务Update流量较大 可能导致分布式死锁的发生 PolarDB-X有一个分布式死锁检测模块可以解决这个问题。死锁解除后 存量同步模块会重试。
首先我们来看一下前文提到的Orphan Data Anomaly问题[2]是怎么发生的 当开启增量数据双写时 PolarDB-X的CN节点内存中的元数据不是同时刷新的 而是有一个先后顺序 所以一定存在一段时间 某些CN节点开启了增量双写 而另一些没有。于是会出现这样的情况
这一问题在Google的Online, Asynchronous Schema Change in F1这篇论文中有过详细的论证。PolarDB-X引入了Online Schema Change 感兴趣的同学可以点击直达文章 以解决此类的问题 在此不再赘述。对于Repartition来说 引入下图中的这些状态 以此保证任意2个相邻状态都是兼容的 不会发生数据一致性问题。我们可以具体来看看其中几个最关键的状态
PolarDB-X以DDL的形式为用户提供拆分规则变更 也就是Repartition 的能力 DDL也需要保障ACID特性 但数据重新分布可能需要花费较长时间 系统因断电等原因而故障在所难免。
所以PolarDB-X也实现了一套稳定的DDL执行框架 它会将DDL分成很多个步骤 每个步骤都是幂等的。这样就可以保证DDL任务可以随时中断 然后恢复继续运行或者回滚。通过DDL将所有的步骤串联 也将所有的人工操作排除在外 开发人员再也不需要做Repartition的方案设计 再也不需要半夜三更手动执行数据库的高危操作了。
MySQL在5.7版本引入Online DDL能力后 使得DDL能够更好地与读写事务并行 相比于之前的版本有了很大的改善。Online DDL的基本原理是只在关键的时刻获取MDL锁 而不是在整个DDL阶段都持有MDL锁。PolarDB-X在执行Repartition时也会分多个阶段获取多次MDL锁 从而允许事务达到更高的并发度。但MDL锁有个危险的特性是 它是一个公平锁 并且可能造成MDL死锁。
多次获取MDL锁提高了性能的同时 实际上增加了MDL死锁产生的概率 而MDL死锁一旦发生 会导致后续所有的读写事务都被阻塞 MySQL的MDL默认超时时间1年 危害远大于普通的数据死锁。因此PolarDB-X也提供了一个分布式MDL死锁检测模块 用于在关键时刻解除分布式MDL死锁。
灵活的拆分规则变更能力是分布式数据库的重要特性。PolarDB-X中有3种表类型 单表、广播表、分库分表。使用拆分规则变更能力 用户可以将数据表进行任意的表类型转换 从而更好地适应业务发展。PolarDB-X在提供拆分规则变更能力的同时 保证了数据的强一致、高可用、对业务透明、并且使用起来非常方便。本文简单阐述了PolarDB-X实现拆分规则变更过程中使用到的各项技术点 如读者可见 我们之所以将拆分规则变更能力集成到数据库内核中 是因为很多数据一致性问题非此不可解决。这也是分布式数据库区别于分布式数据库中间件的重要特性之一。
拆分规则变更能力只是PolarDB-X诸多特性中的一个。想要了解更多内容 欢迎关注公众号内的其他文章。
【相关阅读】
PolarDB-X 让“Online DDL”更Online
鉴于近期加密货币大涨,导致很多小(韭)白(菜)纷纷入场,然后很多人都在问显卡挖...
近期进展 在 ffmpeg-go init 之后,项目也收到了一些关注,还有几个同学发邮件探...
AnalyticDB for MySQL是云端托管的PB级高并发低延时数据仓库 通过AnalyticDB for...
云计算服务正在以前所未有的速度在各行各业快速普及,成为IT应用的最主流实现形...
前言 语言的内存管理是语言设计的一个重要方面。它是决定语言性能的重要因素。无...
场景描述 最近使用 Redis 遇到了一个类似分布式锁的场景,跟 Redis 实现分布式锁...
文本作者:刘晓国,Elastic 公司社区布道师。新加坡国立大学硕士,西北工业大学...
日前 阿里云云效联合阿里云大学团队 面向全国高校学子正式启动了83行代码重构大...
客户介绍 闲鱼是依托阿里电商体系的前台型业务,有非常独特的业务特点和用户诉求...
本文转载自微信公众号「见贤思编程」,作者泰斗贤若如 。转载本文请联系见贤思编...