ICDE 2022|Apache ShardingSphere:一个功能全面和可插拔的数据
相信大家在网上抢购时遇到过网页无法正常访问的情况,一部分原因可能是数据库无法很好地应对不断增加的并发访问。如何有效地解决数据库现有的这些缺陷呢?数据分片是一个可选的方案。本篇文章将为大家解读由重庆大学和 SphereEx 实验室合作的、发表在 CCF A 类数据库顶级会议 ICDE 2022 上的论文《Apache ShardingSphere:A Holistic and Pluggable Platform for Data Sharding》。
问题背景
随着数据量的不断增加以及人们对数据需求的不断增长,需要数据库不仅能够管理大量数据,还能够支持高度并发的访问。设计一种能够应对这两种要求的数据库能够提高用户体验,减少类似网购时网页无法访问的情况出现。
目前来看,关系型数据库仍然是在线事务处理的主力,因为它们支持完整的事务。但是关系型数据库设计初期是针对单台机器的,数据量过大时往往可扩展性欠佳,而且不能很好地解决高并发的问题。尽管现在像 HBase 这种 NoSQL 数据库可以支持高并发请求,但是他们不太适合在线事务的处理,还可能会出现数据不一致的问题。所以很多人开始关注 NewSQL,New 就意味着是从零开始开发的数据库。虽然适合现在的应用场景,但它们还没有很好地接受社会的检验,而且 NewSQL 的使用和维护人员还需要额外地学习相关新技术。
那么在已有的数据库和应用程序之间插入一个数据分片中间件,来连接和管理众多已有的数据库,是不是可行呢?答案自然是肯定的。如下图 1 所示,数据分片中间件将用户查询分配到不同机器内的多个数据库中,分别执行查询后再将多个结果合并,最后返回到应用程序中,这有效地解决了单台机器的限制。对于开发人员来说,数据分片中间件是透明的,使用更为方便。这么看数据分片中间件十分友好且非常高效。
(图 1:数据分片示例)
设计一个好的数据分片中间件存在很大挑战。第一,在不同的场景下采用的底层数据库不同,这些数据库采用不同的数据库协议和 SQL 语句,在一个统一的框架下支持多种数据库并不简单。此外,有许多 SQL 语句类型(从简单的查询到聚合再到多表 join 等),对不同 SQL 语句的路由方法以及合并策略也不相同。第二,多个数据库之间协调事务比较困难,有时候单个事务类型可能不支持所有的场景。第三,数据分片中间件可能会遇到效率问题,因为转发请求、合并结果影响需要消耗一些时间。第四,数据管理员需要逐个配置分片规则,这对他们不是很友好。
Apache ShardingSphere 作为 Apache 第一个顶级开源的数据库分片项目,能够解决了上面提到的所有挑战。ShardingSphere 的主要目标就是要减少数据分片的影响,让开发人员像使用单个数据库一样使用分片数据库。它拥有以下几个显著的特点:
(1)功能完备。ShardingSphere 支持多种主流的关系型数据库(实际上,任何满足 SQL-92 标准的数据库都支持)。它设计并实现了一个完整的 SQL 引擎,因此任何类型的 SQL 都能够准确的被路由。此外,其提供了三种类型的分布式事务和其他丰富的功能。据作者所知,ShardingSphere 是第一个将数据分片、强一致性事务和柔性事务结合在一起的系统。
(2)高效。除了代理模式,ShardingSphere 还提供了 JDBC 的接入方式,这在大部分场景下能够大幅提升效率。此外,ShardingSphere 提出了两种执行模式,并提出了一种智能的策略来选择合适的执行模式和结果合并策略,这能够很好地平衡资源和效率。
(3)可插拔和可扩展。ShardingSphere 基于 SPI(Service Provider Interface, 一种 Java 语言中的服务发现机制)和多种设计模式设计的。因此,更多类型的数据库、功能、分片算法都能够非常方便地加入。此外,所有现有的功能都能够移除或者自由组合。
(4)用户友好。ShardingSphere 支持几乎所有的 SQL 语句,同时隐藏了分布式事务的细节。因此,应用开发人员能够在 ShardingSphere 的帮助下像使用单机版数据库一样使用分布式事务和分片后的数据库集群。ShardingSphere 还提出了一种新的 DistSQL 和 AutoTable 策略,能够帮助数据库管理员更方便地配置分片策略。
当前(截止到论文撰写时期)有 170 多个公司宣布在使用 ShardingSphere。本文基于 2021 年 11 月 10 日发布的 ShardingSphere 5.0.0 版本。
系统框架和数据流
如图 2 所示,ShardingSphere 一共分为五个模块,1)数据源模块,集成多种数据库来进行存储。当前支持的数据源有 MySQL,PostgreSQL,SQL Server,Oracle,MariaDB 和openGauss。2)功能模块,用来提供许多开箱即用的功能,也可以自由地添加、组合、删除功能来满足需求。3)调控器,主要用于配置管理和健康监测。4)SQL 引擎,设计并实现了一个完整的数据分片 SQL 引擎。所有功能都可以通过 SQL 引擎实现可插拔,并且任何功能都可以通过一条 SQL 语句实现。5)适配接口,可以支持不同的场景来使用。
(图 2:ShardingSphere 框架)
图 3 展示了 ShardingSphere 的数据流,主要分为两种。第一种是对 JDBC 进行增强扩展,ShardingSphere-JDBC 可以和 Java 应用程序在同一个进程中运行。第二种是在数据源和应用程序之间的进程 ShardingSphere-Proxy,可以支持使用任何编程语言的应用程序。此外,可以通过任何兼容 MySQL 或 PostgreSQL 协议的终端(如 MySQL 命令客户端、MySQL Workbench 等)直接连接到 ShardingSphere-Proxy,对数据库管理员十分友好。调控器作为一个单独的进程,用来监视数据源并且维护 ShardingSphere-JDBC 和 ShardingSphere-Proxy 配置。
(图 3:ShardingSphere 数据流)
接下来我们从图 2 中的功能模块、调控器、SQL 引擎、适配接口进行细节讲解。
功能模块
3.1 数据分区
数据分区是 ShardingSphere 中最重要的功能之一。它将数据拆分并根据一定的条件将其存储在多个表或数据源(这里的数据源即为逻辑数据库,下同)中。ShardingSphere 提出表分片和数据源分片,每种分片有水平和垂直两种分片方法,下图 4 给出四种类型分片的例子。图 4(a)是原始数据库及其内部表的结构和数据。图 4(c)为垂直表分片、水平表分片、垂直数据源分片以及水平数据源分片四种分片方式。其中分片后的表格结构为 4(b)所示。垂直分片改变了结构,在应用时需要不时调整架构设计,无法很好地满足互联网业务快速变化的需求。相比之下,水平数据分片可以突破单台机器存储量的限制,并且可以更自由地扩展,本文主要对水平分片进行研究。
(图 4:分片实例)
结合图 1 和图 4 我们来解释数据分片中的一些概念:图 1 中的 uid 用来确定数据分片的字段,称其为分片键。ShardingSphere 支持多字段分片键。图 1 中“uid%2”用来将数据记录分配给不同的表,我们称其为分片算法。ShardingSphere 中包含十余种内置分片算法,用户也可以通过接口进行自定义算法。ShardingSphere 还为不同的数据分片需求提供了不同类型的表。例如上图的 t_user,我们称其为逻辑表,而 t_user_h0,t_user_h1 为实际表。真正存储在数据库中的表是实际表,但是应用程序开发人员所看到的表是未经分片的逻辑表。对于应用程序开发人员来说分片操作是透明的。如果在图 4(c)中,如果 t_user 和 t_order 采用相同的分片算法、相同的数据源、相同的分片键和相同的分片算法,我们称它们表为绑定表,这在关联查询时十分有用。此外,我们使用数据节点将逻辑表映射到实际表。它是分片的原子单位,由一个数据源名称和一个实际的表名组成,例如,DS0.t_user_h1。
3.2 分布式事务
ShardingSphere 为不同的使用场景提供了三种类型的分布式事务。
XA 事务。原生 XA 事务共有三个角色:AP、RM、TM,开发人员如果要使用 XA 事务,会有较大的学习成本。ShardingSphere 扮演了 AP 和 TM 的角色,因此开发人员能够像使用单机版事务一样使用 XA 事务。如下图 5,当应用程序向 ShardingSphere 发送“提交”请求,ShardingSphere 将记录日志并启动 2PC(两阶段提交)过程:第一阶段,ShardingSphere 向所有数据源发送“准备”消息,以检查该事务是否可以提交。如果一个数据源确定可以提交它自己的事务,它会向 ShardingSphere 发送一个“ok” ;否则,它会发送一个“no”,并回滚它所做的事情。若所有数据源都“ok”,ShardingSphere 则向所有数据源发送“commit”,否则发送“Rollback”通知回滚。数据源根据命令进行操作。
(图 5:XA 事务)
XA 事务保证了数据的 ACID 特性,但是因为会锁定资源,不太适合长时间事务,ShardingSphere 提供了本地事务和 BASE 事务来解决此问题。
本地事务。如图 6,当 ShardingSphere 接收来自用户应用程序的“COMMIT”或“ROLLBACK”命令时,它会直接把该命令传输到所有数据源。即使某些数据源提交失败,ShardingSphere 也会忽略它。因为 Local 事务没有准备阶段,故可以提高效率。
(图 6:本地事务)
BASE 事务。BASE 事务可以接受短时间内的数据不一致。满足基本可用、软状态和最终一致三个要求的事务称为 BASE 事务。通常,BASE 事务可以从性能上改进系统,因为它们不需要很强的一致性,并且可以减少对共享资源的争用。
(图 7:BASE 事务模型)
ShardingSphere 封装了 SEATA,因为 SEATA 提出了一种自动事务(AT)模式来自动生成补偿操作。如图 7 的灰色框所示,SEATA 中有三个角色:1)事务协调器(TC)维护全局和分支事务的状态,并驱动全局提交或回滚;2)事务管理器(TM)定义全局事务的范围;以及 3)资源管理器(RM)管理资源并驱动分支事务提交或回滚。用户应用程序只需要以标准的数据库连接方式与 ShardingSphere 交互。ShardingSphere 中的 BASE 事务是 2PC 过程,其中 ShardingSphere 扮演 SEATA 中的 TM 和 RM 的角色,BASE 事务过程如图 8 所示。
(图 8:BASE 事务过程)
当然除了数据分片和分布式事务,ShardingSphere 还提供了许多其他有用的功能,包括但不限于:读写拆分、加密、影子(即创建影子数据库并将相应的测试 SQL 路由到它)、伸缩等等。所有这些功能对应用程序开发人员都是透明的,因为 ShardingSphere 可以智能地从标准 SQL 语句中识别必要的信息。而且我们可以根据使用场景自由添加、删除或合并其他功能。更多信息可在我们的用户手册中找到。
调控器
4.1 配置管理
配置信息存储在 Apache ZooKeeper 中,这是一个成熟而强大的分布式协调系统,提供高效的内存管理和分布式锁服务。现在开发者习惯于通过 SQL 操作数据。为此,我们提出了一种新的 DistSQL(分布式 SQL),它允许用户以使用数据库的方式配置 ShardingSphere。DistSQL 分为资源和规则定义语言(RDL)、资源和规则查询语言(RQL)和资源和规则管理语言(RAL):
(1)RDL:用来添加、更改或删除资源和规则。例如:
其中我们提出了 AutoTable 的概念, 我们不需要手动设定分片规则,只需要告诉 ShardingSphere 分片的数据源和应有多少分片,分片的细节就交给 ShardingSphere。
(2)RQL:用来查询和显示现有的资源和规则。例如:
(3)RAL:负责附加的管理员功能,如切换交易类型和扩展。例如:
可看出 DistSQL 和一般 SQL 十分相似,对开发人员很友好。更多信息可参考用户手册。
4.2 健康检测
为了保证高可用性,我们可以建立多个 ShardingSphere-Proxy 实例,并使用负载均衡工具保证负载均衡。调控器会启动一个线程来定期检查每个 ShardingSphere-Proxy 实例和底层数据库的状态,如果发现变化,调控器会自动更改配置,以确保系统仍能正常工作。
SQL 引擎
ShardingSphere 设计并实现了一个完整的 SQL 引擎,用于数据分片和其他功能。因此,ShardingSphere 中的所有功能都可以通过一条 SQL 语句实现。
当一条 SQL 语句到来时,通过 SQL 解析器将其解析成抽象语法树。之后 SQL 路由器根据解析结果将逻辑 SQL 语句与数据节点进行匹配。但是上文我们提到开发人员看到的是逻辑表而不是实际表,所以为了在实际的数据源中进行 SQL 操作,需要通过 SQL 重写器将 SQL 语句重写,重写分为两步,首先进行正确性重写,将标识符重写为实际的标识符(例如将 t_user 重写为 t_user_h0)、派生后续合并所需要的列、修改来自不同数据源的分页、拆分含有批处理的插入语句。这样保证 SQL 语句执行的正确性、避免数据重复。其中可以进行优化重写,对于路由到单节点 SQL 可以只重写标识符不进行其余重写操作提高效率。SQL 执行器将重写后的 SQL 语句发送到底层数据源执行相关操作。下文讲解执行细节。从 SQL 执行器中得到的不同数据源的多个结果进行结果合并,并将结果返回给用户应用程序。
5.1 SQL 执行器
这部分不仅仅是简单向底层数据源转发 SQL 语句,还需要关注数据源连接、内存消耗和最大并发之间的平衡。
SQL Executor 提出了两种连接模式来自动平衡资源控制和执行效率:1) 严格内存模式,它考虑了更多的内存使用,并且不限制一个操作的连接数。在这种模式下,我们更倾向于为每个数据节点维护一个独立的连接,并发执行 SQL,将结果通过数据游标来加载并进行流合并,以避免内存溢出或频繁的垃圾回收;2) 严格连接模式,严格限制每次操作的连接消耗。此模式只能使用将所有结果数据加载到内存中进行合并的内存合并。
然而,对于用户来说很难选择合适的连接方式。此外,即使在相同的应用中,不同的查询可能适合不同的模式。为了方便用户我们设计了自动执行引擎,如下图 9,分为两个阶段。
(图 9:SQL 执行器)
准备阶段。在此阶段,我们首先按数据源对路由和重写结果进行分组。然后,我们根据每个数据源的连接情况确定它们的连接方式。如果路由到数据源的 SQL 数量大于数据源用于查询的最大连接数,就只能采用严格连接模式,否则,我们可以选择严格内存模式。接下来,我们获得所需的连接并创建执行单元。为了避免出现死锁,我们向数据源添加锁来自动获取查询所需的所有连接。
执行阶段。在此阶段,将组中的执行单元一起发送到对应的底层数据源。数据源并行执行 SQL,并为分布式事务或监视发送事件消息。
5.2 结果合并
结果合并将来自不同数据源的多个结果集合并为一个,并将结果返回给用户应用程序。上文提到流合并和内存合并两种合并方式,对于不同的语句我们采用不同的合并方式。
对于迭代语句我们采用流合并的方式,只需要将结果按照数据库游标逐一合并。对于排序(Order by)语句而言,因为每个数据源返回的结果集是有序的,我们采用流合并来使用多路合并算法将这些结果集合并为一个结果集。如果语句同时包含 GROUP BY 和 ORDER BY,并且 GROUP BY 和 ORDER BY 的属性相同,则可以使用流合并。因为组中的数据记录都位于游标所指向的第一位置,如图 10,我们从左到右扫描指向的数据记录(标记为橙色)并累积分数,直到名字不是“Jerry”,输出“Jerry,185”后,调整数据库游标并重复上述操作。其他情况我们需要使用内存合并。
(图 10:GROUP BY 时流合并示例)
此外我们还可以将流合并和内存合并用于聚合语句以及分页操作。
适配器和应用程序
ShardingSphere 包含两个适配器:ShardingSphere-JDBC 和 ShardingSphere-Proxy。前者可以被视为增强的 JDBC 驱动程序。它封装了整个 SQL 引擎和 ShardingSphere 提供的其他功能,可以在任何使用 JDBC 的地方使用。后者是一个代理服务器,它将来自应用程序的请求转发到数据源。它提供了一个连接池,因此不同的应用程序和不同的查询可以共享同一连接。ShardingSphere-Proxy 将自己伪装成 MySQL 或 PostgreSQL 数据库。所以它对应用程序开发人员是透明的,并且支持任何编程语言。
现在全世界已经有许多地方在使用 ShardingSphere 系统比如京东白条、中国电信翼支付等。ShardingSphere 提高了服务质量,降低了开发成本。
实验
数据集:1)Sysbench,这是一个著名的数据库基准测试工具,它提供了一个表格,允许用户调整其数据量。2)TPCC,一个广泛使用的 OLTP 基准,它模拟了商店经常使用的几种交易类型。它的 10 个表按仓库组织(每个仓库约 600,000 个条目)。
对比方法:MySQL v5.7.26(MS);PostgreSQL v10.17(PG);Vitess v12.0.0;Citus v9.0.0;TiDB v5.2.0;CockroachDB v21.1.11(CRDB);Aurora MySQL v2.07.2;Aurora PostgreSQL v4.2。
我们在华为云中使用了一个由 12 台虚拟服务器组成的集群,每台服务器都配备了 CentOS 7.1 64 位、32-VCORE CPU、64 GB 内存和 1TB 磁盘。
对比实验。使用 Sysbench 进行比较,如下表所示,基于 ShardingSphere 的系统在所有场景中总是表现最好的。
使用 TPCC 进行比较,TPCC 提供了五个场景,每个场景的比例是固定的,所以我们只给出整体表现。如图 11 可看出 SSJ 效果最好。
(图 11:不同分布式系统的比较)
可伸缩性实验。接下来我们只与 TiDB 进行对比,因为它相比于别的系统性能最优。如图 12,基于 SSJ 的系统总是执行得最好。
(图 12:不同数据量)
不同的并发数,如图 13 基于 SSJ 的系统在 TPS 方面表现最好。
(图 13:不同并发数)
不同的数据服务器,如图 14,TPS 先略有增加,然后在数据服务器数量超过 3 台时保持稳定。原因可能有两个。首先,我们只使用一个代理服务器,这可能是一个瓶颈。其次,随着数据服务器的增多,网络可能成为另一个瓶颈。
(图 14:不同数据服务器数量)
我们验证的绑定表的有效性,图中 Common 是没有绑定关系的表查询的性能,可明显看出远远不如有绑定关系的绑定表的效率。
(图 15:绑定表的性能)
我们测试了不同最大连接数 MaxCon 对效率的影响,如图 16。
(图 16:最大连接数的效率)
总结
本文介绍了开源数据分片系统 Apache ShardingSphere,它允许用户像使用一个数据库一样使用分片数据库。在两个著名的基准测试工具上进行了广泛的实验,验证了在我们的设置下, ShardingSphere 的性能在大多数情况下都优于其他分片系统和新架构的数据库。越来越多的公司正在将 ShardingSphere 用于其关键的应用程序。在未来的工作中,我们将提供基于 ShardingSphere 的“数据库+”产品,并构建一个具有更多可插拔功能的生态系统。
(来源公众号: ShardingSphere官微)