我们是怎样打造一款分布式数据库的

关系型数据库在过去数十年的数据库领域一直占据着绝对主导的地位,它所带来的稳定性、安全性和易用性,成为了构建现代化系统的基石。随着的互联网高速发展,构架于单机系统的数据库已无法满足越来越高的并发请求和越来越大的数据存储需求,因此,分布式数据库被愈加广泛的采用。 一直以来,数据库领域均由西方的科技公司和社区所主导。而今,越来越多的国产数据库解决方案以分布式为支点,逐渐地在此领域有所建树。Apache ShardingSphere是其中的一个分布式数据库解决方案,也是目前Apache软件基金会中唯一的数据库中间件。

背景

全面兼容面向传统关系型数据库的SQL和事务,并且对分布式的天然友好,是分布式数据库解决方案的设计目标。它的核心功能主要集中在以下几点:

  • 分布式存储:数据存储不受单机磁盘容量限制,可通过增加数据服务器的数量提升存储能力;
  • 计算存储分离:计算节点无状态,可通过水平扩展增加算力。存储节点和计算节点能够分层优化;
  • 分布式事务:高性能、完全支持本地事务ACID原义的分布式事务处理引擎;
  • 弹性伸缩:可以随时随地的在不影响现有应用的情况下,动态对数据存储节点扩容和缩容;
  • 多数据副本:自动将数据以强一致、高性能的方式复制至跨机房的多个副本,以保证数据的绝对安全;
  • HTAP:采用同一套产品混合处理OLTP的事务型操作和OLAP的分析型操作。

分布式数据库的实现方案可以划分为进取型和稳定型。进取型实现方案是指开发全新架构的NewSQL。这类产品以追求更高性能换取稳定性的缺失和运维经验的不足;稳定型的实现方案是指在现有数据库的基础上提供增量能力的中间件。这类产品则以牺牲部分性能以保证数据库的稳定性和运维经验的复用。

架构

Apache ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。 它们均提供标准化的数据分片、分布式事务和分布式治理等功能,可适用于如Java同构、异构语言、云原生等各种多样化的应用场景。随着Apache ShardingSphere在查询优化器和分布式事务引擎的不断探索,它已渐渐地打破了实现方案的产品边界,向集进取型和稳定型于一身的平台级解决方案演进。

Sharding-JDBC

定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

Sharding-Proxy

定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。目前已提供MySQL和PostgreSQL版本,它可以使用任何兼容MySQL和PostgreSQL协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat等)操作数据,对DBA更加友好。

Sharding-Sidecar(规划中)

定位为Kubernetes的云原生数据库代理,以Sidecar的形式代理所有对数据库的访问。 通过无中心、零侵入的方案提供与数据库交互的的啮合层,即Database Mesh,又可称数据库网格。

计算存储分离的混合架构

Sharding-JDBC采用无中心化架构,适用于Java开发的高性能的轻量级OLTP应用;Sharding-Proxy提供静态入口以及异构语言的支持,适用于OLAP应用以及对分片数据库进行管理和运维的场景。

每种架构方案都有其各自的优缺点,下面表格对比了各种架构模型的在不同场景下的优劣:

Apache ShardingSphere是多接入端共同组成的生态圈。通过混合使用Sharding-JDBC和Sharding-Proxy,并采用同一配置中心统一配置分片策略,能够灵活的搭建适用于各种场景的应用系统,使得架构师更加自由的调整适合与当前业务的最佳系统架构。

Apache ShardingSphere采用Share Nothing架构,它的JDBC和Proxy接入端均采用无状态设计。作为计算节点,Apache ShardingSphere负责对获取的数据进行最终的计算汇总。由于本身并不存储数据,因此Apache ShardingSphere可以将计算下推至数据节点,以充分利用数据库自身的计算能力。Apache ShardingSphere可以通过增加部署节点数量来增加计算能力;增加数据库节点数量来增加存储能力。

核心功能

数据分片、分布式事务、弹性伸缩和分布式治理是Apache ShardingSphere目前阶段的4个最核心功能。

数据分片

分而治之是Apache ShardingSphere用于处理海量数据的方案。Apache ShardingSphere通过数据分片方案,使数据库具备分布式存储能力。

它可以将SQL根据用户预置的分片算法自动路由至相应的数据节点,以达到操作多个数据库的目的。用户可以像使用单机数据库一样使用被Apache ShardingSphere所管理的多个数据库。目前支持MySQL、PostgreSQL、Oracle、SQLServer以及任何支持SQL92标准和JDBC标准协议的数据库。数据分片的内核流程见下图:

主要流程如下:

1、通过解析数据库协议包或JDBC驱动获取用户输入的SQL和参数;

2、根据词法分析器和语法分析器将SQL解析为AST(抽象语法树),并提取分片所需信息;

3、根据用户预置算法匹配分片键,并计算路由路径;

4、将SQL改写为分布式可执行SQL;

5、向各数据节点并行发送SQL,执行引擎负责连接池与内存资源的平衡;

6、根据AST执行流式或全量内存结果集归并计算;

7、封装数据库协议包或JDBC结果集,并返回至客户端。

分布式事务

事务是数据库系统的最核心功能。分布式的不确定和事务的复杂性,决定了分布式事务领域无法出现放之四海而皆准的方案。

面对百花齐放的现状,Apache ShardingSphere提供高度开放的方案,采用标准接口统一整合开发者自主选择的第三方分布式事务框架,以满足各种场景的应用需求。除此之外,Apache ShardingSphere还提供了全新的分布式事务解决方案JDTX,来弥补现有方案的缺失。

标准化整合接口

Apache ShardingSphere为本地事务、两阶段事务和柔性事务提供了统一的适配接口,并对接了大量的现有第三方的成熟解决方案。通过标准接口,开发者可以轻松的将其他整合方案融入到Apache ShardingSphere平台中。

然而,融合大量第三方解决方案,却不能覆盖所有分布式事务需求分支。各种解决方案均有各自的适合及不适合场景。各解决方案间是互斥的,无法将它们的优点叠加使用。针对于当前最常见2PC(两阶段提交)和柔性事务,分别存在着以下的优势和不足:

  • 两阶段提交:基于XA协议实现的两阶段分布式事务对业务侵入很小。 它最大的优势是对使用方透明,开发者可以像本地事务一样使用基于XA协议的分布式事务。 XA协议能够严格保障事务ACID特性,但这也是一把双刃剑。事务执行在过程中需要将所需资源全部锁定,它更加适用于执行时间确定的短事务。 对于长事务来说,整个事务进行期间对资源的独占,将导致对热点数据依赖的业务系统并发性能衰退明显。 因此,在高并发的性能至上场景中,基于XA协议两阶段提交类型的分布式事务并不是最佳选择。
  • 柔性事务:如果将实现了ACID的事务要素的事务称为刚性事务的话,那么基于BASE事务要素的事务则称为柔性事务。 BASE是基本可用、柔性状态和最终一致性这3个要素的缩写。在ACID事务中对一致性和隔离性的要求很高,在事务执行过程中,必须将所有的资源占用。柔性事务的理念则是通过业务逻辑将互斥锁操作从资源层面上移至业务层面。通过放宽对强一致性和隔离性的要求,只要求当整个事务最终结束的时候,数据是一致的。而在事务执行期间,任何读取操作得到的数据都有可能被改变。这种弱一致性的设计可以用来换取系统吞吐量的提升。

基于ACID的两阶段事务和基于BASE的最终一致性事务都不是银弹,可通过下表详细对比它们之间的区别。

缺乏并发度保障的两阶段事务不能称之为完善的分布式事务解决方案;而缺乏对ACID原义支持的柔性事务都甚至不能称之为数据库事务,它更适合服务层的事务处理。

放眼当前,实难找到无需权衡即可放之四海而皆准的分布式事务解决方案。

新一代分布式事务中间件JDTX

JDTX是京东数科自研的分布式事务中间件,尚未开源。它的设计目标是强一致(支持ACID的事务原义)、高性能(不低于本地事务性能)、1PC(完全摒弃两阶段提交和两阶段锁)的完全分布式事务中间件,目前可用于关系型数据库。它采用完全开放SPI的设计方式,提供与NoSQL对接的可能,未来能够将多元异构数据维持在同一事务中。

JDTX通过完全自研的事务处理引擎,将SQL操作的事务中数据转化为KV(键值对),并在其基础上实现了MVCC(多版本快照)的事务可见性引擎,以及与数据库设计理念类似的WAL(预写日志系统)存储引擎。可以通过下面的架构图来了解一下JDTX的构成:

它的设计特点是将在事务中的数据(称之为活跃数据)和不在事务中的数据(称之为落盘数据)分离。活跃数据在落盘至WAL之后,再以KV的形态保存至MVCC内存引擎中。落盘数据则是通过异步刷盘的方式,将WAL中的REDO日志,以流量可控的方式同步至最终的存储介质中(如:关系型数据库)。事务内存查询引擎负责使用SQL从KV格式的活跃数据中检索到相关数据,与落盘数据合并,并根据事务隔离级别获取符合当前事务可见的数据版本。

JDTX以全新的架构重新诠释了数据库的事务模型,主要亮点有:

1、内化分布式事务为本地事务

JDTX的 MVCC引擎是一个集中式缓存。它能够将两阶段提交内化至一阶段提交,以维持单一节点中数据的原子性和一致性,即将分布式事务的范畴缩减到本地事务的范畴。JDTX通过保证所有对事务数据的访问都通过MVCC引擎的活跃数据 + 最终数据端的落盘数据的合并的方式,以保证事务数据的原子性和一致性。

2、无损的事务隔离机制

以MVCC的方式实现事务隔离性。目前完整的支持4种标准隔离级别中的读已提交和可重复读,已经可以满足绝大部分需求。

3、高性能

采用将活跃数据异步刷盘至存储介质的方式,极大地提高了数据写入的性能上限。它的性能瓶颈从数据库写入耗时转移到了落盘至WAL和MVCC引擎的耗时。

与数据库的WAL系统类似,JDTX的WAL也采用顺序日志追加的方式,因此可以简单的理解为JDTX的WAL耗时 = 数据库系统的WAL耗时。而MVCC引擎则采用KV数据结构,其写入耗时小于维护BTree索引的数据库。因此,JDTX的数据更新性能的上限甚至可以高于不开启事务。

4、高可用

WAL和MVCC引擎均可以通过主备 + 分片的方式维持高可用和水平扩展的能力。在MVCC引擎完全不可用的情况下,可通过恢复模式将WAL中的数据同步至数据库,以保证数据的完整性。

5、跨多元数据库事务

将事务活跃数据和落盘数据分离的设计方案,使其落盘数据存储端无任何限制。由于事务活跃数据通过异步的落盘执行器存储至后端存储介质,因此后端是否为同构数据库,其实并无影响。使用JDTX能够保证跨多元存储端(如:MySQL、PostgreSQL,甚至是MongoDB、Redis等NoSQL)的分布式事务维持在同一事务语义之中。

通过Apache ShardingSphere提供的分布式事务统一适配接口,可以将JDTX像其他第三方分布式事务解决方案一样轻松地融入Apache ShardingSphere生态,将数据分片与分布式事务无缝结合,使它们具备组成分布式数据库基础设施的能力。架设在产品最前端的Apache ShardingSphere用于SQL解析、数据库协议和数据分片;位于中层的JDTX用于通过KV和MVCC的方式处理事务活跃数据;最底层的数据库则仅作为最终的数据存储端。下图是ShardingSphere + JDTX的架构图。

可以说,JDTX的存在,使得Apache ShardingSphere打破了稳定型的数据库中间件的定位,在保持稳定的同时,逐步向进取型NewSQL发展。

弹性伸缩

与无状态的服务化应用不同,数据节点中均持有不可丢失的重要用户数据。当数据节点的容量不足以承担快速增长的业务时,数据节点的扩容则在所难免。根据用户预置的分片策略不同,扩容的策略也会随之不同。

弹性伸缩可以让被Apache ShardingSphere所管理的数据库在不停止对外服务的情况下进行扩容和缩容。弹性伸缩分为弹性迁移和范围扩容两个组件,目前它们均在孵化中。

弹性迁移

数据迁移是面向用户定制分片策略的标准扩缩容方案。在迁移过程中,需要准备两套数据节点。原数据节点在继续提供服务的同时,将数据以存量和增量的方式,分别写入新数据节点。整个迁移过程无需停止对外服务,可以平顺的过渡新旧数据节点。Apache ShardingSphere还将提供工作流界面,让迁移过程完全自主可控。 弹性迁移的架构图如下:

具体流程如下:

1、通过配置中心修改数据分片配置,以触发迁移流程。

2、记录当前迁移数据开启前的位点之后,开启历史迁移作业,分批迁移全量数据。

3、开启Binlog订阅作业,迁移位点之后的增量数据。

4、根据采样率设置比对数据。

5、设置原数据源只读,确保实时数据迁移完成。

6、将应用连接切换至新数据源。

7、旧数据源下线。

迁移时长根据数据量的大小可能是几分钟至几周不等。迁移过程中可以随时回退或重新迁移。整个迁移流程完全自主可控,降低迁移过程中的风险;并且通过自动化工具完全屏蔽人工操作,避免繁琐的操作带来的巨大工作量。

范围扩容

如果弹性迁移称之为硬伸缩的话,那么范围扩容则称之为软伸缩。Apache ShardingSphere的范围扩容不涉及内核改造,也无需迁移数据,它只需通过优化范围分片策略,即可达到自动扩(缩)容的目标。使用范围扩容,用户无需感知分片策略和分片键等分库分表方案中必要概念,让Apache ShardingSphere更加接近一体化的分布式数据库。

使用范围扩容的用户,只需向Apache ShardingSphere提供数据库资源池。容量巡检器会在表容量到达阈值时,从资源池中依次寻找下一个数据节点,并在新数据节点创建新表之后,修改分片策略的范围元数据。当资源池中没有新数据节点后,Apache ShardingSphere会按照同样的顺序,在已经创建过表的数据库中增加新表。 当表数据大量删除时,之前的数据节点的数据将不再紧凑,垃圾回收器会定时压缩表范围,以释放更多的碎片空间。范围扩容的结构如下:

Apache ShardingSphere为不同的应用场景,提供了更加灵活的弹性伸缩策略。目前仍在孵化中的两个弹性伸缩相关的项目,也力争尽快提供试用版本。

分布式治理

治理模块的设计目标是为了更好管理和使用分布式数据库。

数据库治理

与所有的分布式系统的设计理念一脉相承,分而治之同样是分布式数据库的指导方针。数据库治理能力的存在,能够让管理成本不随着数据库实例数目的增长而提升。

配置动态化

Apache ShardingSphere使用配置中心来管理配置,可以在配置修改后的极短时间内传播到所有的接入端实例。配置中心采用开放的SPI方式,能够充分利用配置中心自身的能力,如配置多版本变更等。

高可用

Apache ShardingSphere使用注册中心管理接入端实例和数据库实例的运行状态。注册中心同样采用配置中心的开放SPI方式。部分注册中心的实现可以涵盖配置中心的能力,因此用户可以叠加使用注册中心和配置中心的能力。

Apache ShardingSphere提供了数据库实例禁用和接入端熔断的能力,分别用于处理数据库实例不可用和接入端被大流量冲击的场景。

Apache ShardingSphere目前正在孵化高可用的SPI,让用户能够复用数据库自身提供的高可用方案。目前正在对接MySQL的MGR高可用方案。Apache ShardingSphere可以通过自动探知MGR的选举变化并快速传播至所有的应用实例。

可观察性

大量数据库和接入端实例,使得DBA和运维人员无法迅速感知当前系统的状况。Apache ShardingSphere通过对OpenTracing协议的实现,将监控数据发送至实现其协议的第三方APM系统中;除此之外,Apache ShardingSphere还提供了Apache SkyWalking的自动探针,可以让使用它作为可观察性产品的用户直接观测到Apache ShardingSphere的性能、调用链关系以及系统的整体拓扑图。

数据治理

得益于Apache ShardingSphere对SQL灵活的处理能力和对数据库协议的高度兼容性,数据相关的治理能力也被很方便的加入到了产品生态中。

脱敏

Apache ShardingSphere可以让用户在无需修改代码的情况下,自动将指定的数据列加密后存储至数据库,并在应用程序获取数据时解密,以保证数据的安全。当数据库的数据被不慎泄露时,敏感数据信息由于被完全加密,从而不会造成更大的安全隐患。

影子库表

Apache ShardingSphere可以在系统进行全链路压测时,自动将用户标记的数据路由至影子库(表)。影子库(表)压测功能可以让线上压测成为常态,用户无需在关心压测数据的清理。此项功能也正在高速的孵化中。

线路规划

如您所见,Apache ShardingSphere正处于高速发展的轨道中,越来越多与“分库分表”这条曾经主线并无强关联的功能被加入其中。但这些产品功能却并不突兀,它们反而能助力Apache ShardingSphere成为更加多元化的分布式数据库解决方案。Apache ShardingSphere未来的线路主要会集中在以下几点。

可插拔平台

越来越多的零散功能需要进一步梳理。Apache ShardingSphere现有的架构还不足以完全吸收如此广泛的产品功能。弹性化的功能可插拔平台是Apache ShardingSphere未来架构的调整方向。

可插拔平台会将Apache ShardingSphere从技术和功能两方面完全拆开。Apache ShardingSphere的全景图如下所示:

Apache ShardingSphere会根据技术架构横向分为4层,分别是接入层、SQL解析层、内核处理层和存储访问层;并且将功能以可插拔的形态融入至4层架构中。

Apache ShardingSphere对数据库类型的支持将完全开放,除了关系型数据库,NoSQL也会完全开放支持,数据库方言互不影响,完全解耦。在功能方面,Apache ShardingSphere采用叠加式架构模型,使各个功能可以灵活的组合使用。每个功能模块只需关注自身的核心功能,由Apache ShardingSphere架构负责功能的叠加组合使用。即使没有任何功能,Apache ShardingSphere也可以作为一个空白的接入端直接启动,为开发者的定制化开发提供脚手架以及SQL解析等基础设施。融入Apache ShardingSphere生态的数据库,将直接获得平台提供的所有基础能力;在Apache ShardingSphere平台上开发的功能,也将直接获得已接入平台的数据库类型的全部支持。数据库类型和功能类型将以相乘的方式排列组合,基础设施 + 乐高的组合,将为Apache ShardingSphere提供各种想象和提升的空间。

查询引擎

目前Apache ShardingSphere只是将SQL通过正确的路由和改写,分发至相应的数据库以操作数据。计算下发能够充分利用的数据库的查询引擎,但无法有效的支持复杂关联查询和子查询。基于关系代数实现的SQL on KV查询引擎随着JDTX的开发日臻成熟,将其积累的经验反哺于SQL查询引擎,能够让Apache ShardingSphere更好的支持子查询和跨库关联查询等复杂查询。

多数据副本

分布式数据库所需要的多数据副本能力目前的Apache ShardingSphere还未具备。未来Apache ShardingSphere将提供基于Raft的多副本写入能力。

Database Mesh

上文中提到的Sharding-Sidecar接入端,是Apache ShardingSphere未来的第三个接入端形态,旨在更好的与Kubernetes配合,打造云原生数据库。

Database Mesh的关注重点在于如何将分布式的数据访问应用与数据库有机串联起来,它更加关注的是交互,是将杂乱无章的应用与数据库之间的交互有效的梳理。使用Database Mesh,访问数据库的应用和数据库终将形成一个巨大的网格体系,应用和数据库只需在网格体系中对号入座即可,它们都是被啮合层所治理的对象。

Data Federation

支持更多的数据库类型之后,Apache ShardingSphere会将工作重点放在多元异构的数据库类型的统一查询引擎之上。除此之外,Apache ShardingSphere还将配合JDTX,将更加多元的数据存储介质纳入到同一事务中。

开源与社区

Apache ShardingSphere在2016年1月17日在GitHub平台首次开源,开源项目的初始名称是Sharding-JDBC。在2018年11月10日,ShardingSphere改名并正式进入Apache软件基金会的孵化器。

在开源至今走过的4年里程中,Apache ShardingSphere的架构模型在不断的演进的同时,整体产品的功能范围也在急速地扩张。它从开源之初的分库分表Java开发框架,逐渐演化为分布式数据库解决方案。

随着Apache ShardingSphere的生态圈的扩张,由少数开发者掌控项目的状态早已被打破。目前的Apache ShardingSphere有近百名贡献者,以及近20名核心提交者,他们共同打造着这个遵循着Apache Way的社区。Apache ShardingSphere是一个标准的Apache软件基金会开源项目,并不受某一商业公司或某几位核心开发者掌控。

目前有超过100家公司明确的声明他们在使用Apache ShardingSphere,读者可以从官方网站找到采用公司的用户墙。

随着社区的成熟,Apache ShardingSphere的成长也越来越迅速。我们诚邀感兴趣的开发者一同参与到Apache ShardingSphere社区中,完善不断扩大的生态。

项目地址:

https://github.com/apache/incubator-shardingsphere

作者介绍:

张亮,京东数科数据研发负责人,Apache ShardingSphere发起人 & PPMC,JDTX负责人。

热爱开源,主导开源项目ShardingSphere(原名Sharding-JDBC)和Elastic-Job。擅长以java为主分布式架构,推崇优雅代码,对如何写出具有展现力的代码有较多研究。

目前主要精力投入在将ShardingSphere和JDTX打造为业界一流的金融级数据解决方案之上。ShardingSphere已经进入Apache孵化器,是京东集团首个进入Apache基金会的开源项目,也是Apache基金会首个分布式数据库中间件。

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/GZSNO1AmGwkDB02eQzFt
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券