当前位置: 主页 > 数据库

开源分布式内存数据库-开源分布式存储软件

发布时间:2023-02-10 10:24   浏览次数:次   作者:佚名

PolarDB-X的前身是淘宝内部使用的TDDL(2007年,Java库形式)。 早期DRDS(2012年研发,2014年上线,以数据库和表中间件+MySQL Proxy的形式)品牌在阿里云上提供服务,后期(2019年)正式转型为分布式数据库PolarDB-X(正式成为PolarDB品牌的一员)。 从中间件到分布式数据库,我们在以MySQL为存储构建分布式数据库的道路上走过了10多年。 在这个过程中,我们积累了很多技术,也走了一些弯路。 未来,我们将继续坚定前行。

PolarDB-X的发展历程主要分为中间件(DRDS)和数据库(PolarDB-X)两个阶段,这两个阶段之间存在着巨大的差异。 笔者参与PolarDB-X的开发整整十年,经历了整个开发过程。 今天和大家聊一聊PolarDB-X开发改造过程中的一些趣事。

中间件时代(2012~2019)

DRDS时期的开发思路其实很简单,主要满足用户的几个需求:

阿里云提供的RDS MySQL单实例最大存储空间有限(比如早期只有2T)

Share Storage数据库可以解决磁盘容量的问题,但是仍然受限于单机的CPU\内存,无法解决写扩展性的问题

使用开源中间件可以解决以上问题,但是扩容等运维操作非常麻烦和复杂

在这样的背景下,我们在中间件TDDL之上加了一个MySQL Proxy(其实是Cobar的网络层),部署在阿里云上,成为了最早的DRDS。

上云之始--用云,服务云

值得一提的是,DRDS上云的方式现在很流行。

和阿里云的普通用户一样,也有一个阿里云账号(不过这个账号有万亿的授信额度),用这个账号的AK/SK调用阿里云各个产品的Open API,进行各种任务。 操作。

开源分布式文件系统_开源分布式内存数据库_开源分布式存储软件

比如创建实例时,会购买ECS来部署DRDS节点; 你会在它前面购买SLB用于负载均衡; 您将购买SLS服务来存储实例的SQL审计; 您将打通从 DRDS 节点到用户 RDS 等的网络。

这种管控架构形式目前被广泛应用,充分利用了云端的优势。 DRDS几乎不需要关注资源问题,不需要自己维护库存; 对于机器宕机等问题,ECS也可以自动迁移(连IP都不会变),非常方便。 让DRDS的研发团队更专注于提升产品本身的能力。

一方面,DRDS在阿里云上为用户提供服务,另一方面,作为阿里云的“普通用户”,享受云技术带来的好处,也是一件很有趣的事情。

在DRDS期间,我们在核心重点上积累了以下技术能力:

SQL 语义与 MySQL 的兼容性

TDDL只服务于内部用户,而淘宝的研发规范比较严格,应用使用的SQL是比较简单的类型,所以对SQL的处理很少。 简单的说,它甚至不需要理解 SQL 的语义,直接转发即可。 但是,用户在云端的需求是多种多样的,已有大量的应用迁移到云端,因此对SQL兼容性的要求也变得更高了。 这就需要我们提供完整的SQL引擎。

与市面上的TDDL等分库分表中间件相比,DRDS多了两个关键组件:查询优化器和执行器,并带有完整的算子系统。 它的目标是无论 SQL 多么复杂,都能正确理解其语义并执行正确的结果。

有很多工作需要长期积累。 举几个例子:

类似这样的任务还有很多,比如类型系统(zhuanlan.zhihu.com/p/374130246)、sql_mode、时区系统、默认值等等,虽然繁琐但是很有必要。 这些工作都很好地延续到了 PolarDB-X 上。

极限下推优化

将计算下推到离数据最近的地方,是保证性能最简单的原则。

使用MySQL作为分布式数据库的存储引擎,其实本身就具有强大的计算能力。 特别是相对于目前很多使用KV作为存储引擎的分布式数据库来说,大多只能实现filter和function pushdown execution。 但是,MySQL 支持完整的 SQL 执行。 尽可能多地将分片级别的JOIN、子查询、聚合操作下推到MySQL,是DRDS保证高性能的关键。

下表简单对比了行业产品的一些优化选项,信息来源于公开文档:

开源分布式内存数据库_开源分布式存储软件_开源分布式文件系统

推动太多会导致错误的结果,而推动太少会导致性能不佳。 DRDS的优化器积累了大量的下推优化策略。 这些优化策略大多不能凭空想象,只能通过实际场景案例积累。 看:

zhuanlan.zhihu.com/p/366312701。

物理算子的丰富性和MPP的执行引擎

物理算子是指执行者的各种算法。 比如Join,我们支持HybridHashJoin、LookupJoin、NestedLoopJoin、SortMergeJoin、MaterializedSemiJoin等算法。

DRDS最初只支持单线程执行SQL,但是这种执行对于复杂的SQL是不够的。 我们先做了一个独立的并行引擎(SMP),然后发展到现在的MPP引擎,zhuanlan.zhihu.com/p/346320114。

同时,执行引擎还支持spill out(将中间结果放到磁盘的能力),即使只有15M内存,也能跑通TPCH 1G测试。 详见:zhuanlan.zhihu.com/p/363435372。

这些能力的积累和突破,大大提升了PolarDB-X面对复杂SQL的计算能力。

颠簸的分布式事务

分布式事务是一个无法回避的问题。

对于中间件产品,我们有一个非常基本的假设:使用标准的MySQL,避免对MySQL进行侵入式修改; 即使修改,也应该是插件。

在不修改MySQL的情况下,我们已经很久没有很好的实现分布式事务了。

我们来回走过的一些弯路:

和传统的中间件一样,禁止分布式事务。 但是这种应用的改造成本太高了。

使用灵活事务,我们很早就使用了GTS(原TXC)等第三方组件来实现分布式事务。 该方案需要根据不同SQL的语义来实现回滚语句,SQL兼容性很差。

使用 GTM 的方案。 GTM本质上是一个单点,GTM和Coordinator之间有大量的数据交互。 性能太差,不能用作默认的事务策略。 所以我们再看使用GTM方案的“数据库”,肯定有非常严格的使用条件(比如要求应用尽量避免分布式事务,默认关闭强一致性等)。

XA事务,早期的MySQL对XA的支持很弱,bug很多(其实MySQL对XA的bug还是很多的)开源分布式内存数据库,比如宕机恢复过程因为XA很容易挂掉。 而且XA事务无法解决读可见性问题,与单机事务的行为不兼容。

交易系统与存储层密切相关。 从PolarDB-X的探索来看,不对MySQL进行深入改造,是不可能做出性能和功能满足要求的分布式事务的。 这是所有中间件产品都无法解决的问题,也是中间件与数据库的根本区别。

不可避免的分区键

从第一次使用DRDS开始,我就一直要回答一个问题,如何为我的表选择分区键?

从“高吞吐量”和“高并发”的业务系统来看,要求表和SQL有具有业务特性的partition key是非常合理的。 将所有内容下推到存储层以避免跨机器查询和事务。 只有这样才能保证最好的性能,也就是性能的天花板。

问题是,虽然这个上限很高(淘宝双十一0点的业务高峰也可以很顺利),但是:

这种转换的成本非常高,很多时候分区键很难选择。比如很多电商系统的订单表会有两个查询维度,seller和buyer,选择哪个作为分区键分区键

并不是所有的业务系统(或者不是所有的表和SQL)都值得这么高的成本去改造,只有核心系统中的核心逻辑才需要做这种细致的改造

如果split key选错了,下限会极低。 对于数据库,提供相对较高的上限与提供不太低的下限同样重要。

自然而然,我们想知道什么样的技术可以让你“忘记”分区键。

数据库时代(2019~)

通向透明分配之路

是否有必要强制应用程序关心分区键的概念是中间件和数据库之间的关键区别之一。

分区键和全局索引

广泛的“分区键”的概念并不是分布式数据库独有的。

在我们的独立数据库中,例如 MySQL,数据存储为 B 树。 如果一个表只有主键开源分布式内存数据库,那么它只有一个 B 树,例如:

CREATE TABLE t1(id INT, name CHAR(32), addr TEXT, PRIMARY KEY (id))

该表的唯一 B 树按主键 (id) 排序。 如果我们的查询条件包含了id的等价条件,比如where id=14,那么我们就可以在这棵树中快速定位到这个id对应的记录; 否则,我们需要执行全表扫描。

开源分布式文件系统_开源分布式存储软件_开源分布式内存数据库

B-tree中用于排序的key可以通过二分查找定位到一个叶子节点; partition key可以通过Range上的hash或者binary search定位到一个fragment。 可以看出,都是为了快速定位数据。

如果我们要查询上表where name='Megan',在MySQL中,我们不需要将name设置为主键。 一种更自然的方法是在名称上创建二级索引:

在 t1(名称)上创建索引 idx

每一个二级索引在MySQL中都是一个独立的B树,用于排序的key是二级索引的列。 也就是说,当前表t1有两棵B树,一颗为主键,一颗为idx,分别是:

id->name, addrname->id

使用where name='Megan'查询时,会先访问idx的B树,根据name='Megan'定位叶子节点,获取id的值,然后将id的值用于B树的主键,找到完整的记录。

开源分布式内存数据库_开源分布式文件系统_开源分布式存储软件

二级索引实际上使用了冗余数据,使用了空间,增加了写入的成本来换取查询性能。

同时,二级索引的维护成本也不是很高。 通常,您可以安全地在一个表上创建多个二级索引。

同样,在分布式数据库中,“忘记”分区键的唯一方法是使用分布式二级索引,也称为全局索引(Global Index)。 并且这个全局索引需要高效、廉价并且与传统的二级索引高度兼容。

全局二级索引也是一种数据冗余形式。 例如,执行 SQL 时:

INSERT INTO t1 (id,name,addr) VALUES (1,"meng","hz");

如果orders表上有seller_id的全局二级索引,可以简单理解为我们分别在主键和seller_id的两个全局索引中执行这个insert,一共写入两条记录:

INSERT INTO t1 (id,name,addr) VALUES (1,"meng","hz");INSERT INTO idx (id,name) VALUES (1,"meng");

t1主键索引的分区键是id,idx的分区键是name。

开源分布式文件系统_开源分布式内存数据库_开源分布式存储软件

同时,由于这两条记录不太可能在同一个DN上,为了保证这两条记录的一致性,我们需要将这两次写入封装成一个分布式事务(这点不同于单机数据库,二级Index同样由单机事务写入)。

当我们所有的DML操作通过分布式事务维护全局索引时,二级索引和主键索引可以一直保持一致的状态。

似乎全球指数听起来也很容易? 它不是。

全局索引和分布式事务

索引必须是强一致的,例如:

这里对索引的一致性要求其实就是对分布式事务的要求。

由于全球指数的引入,100%的交易将是分布式交易。 对分布式事务的要求与“强依赖分区键类型的分布式数据库”完全不同,要求变得更高:

至少要达到SNAPSHOT ISOLATION以上的隔离级别,否则行为会和单机MySQL有很大的不同,会有非常大的数据一致性风险。 目前常见的解决方案有HLC、TrueTime、TSO、GTM。 如果数据库没有使用这些技术,则需要仔细筛选。

与TPCC模型的10%分布式事务相比,100%分布式事务对性能的要求更高。 HLC、TSO、TrueTime方案都可以实现比较大的交易容量。 相对来说,GTM更重一些,其上限比TSO低很多,同样是单点方案(TSO虽然是单点,但是由于Grouping的优化,容量可以做的很大) .

即使使用了TSO/HLC等解决方案,也必须进行优化,例如典型的1PC、Async Commit等优化。 否则,维护索引增加的响应时间将是不可接受的。

与独立索引的兼容性

另外,在单机数据库中,索引有一些看似自然的行为,也需要兼容。

例如:

创建索引的速度、索引回表的性能、索引的功能限制、聚簇索引、索引的存储成本等等,其实都极大地影响了全局索引的使用体验。 继续扩大。

索引数

这些对全局索引的要求,本质上是从全局索引的数量上推导出来的。

对于透明性好的数据库,所有的索引都会是全局索引,而且全局索引的数量会非常多(就像单机数据库中一张表和一个库的二级索引数量一样)。 数量越大,要求越高。

但是,对于这些没有完全准备好的分布式数据库,即使有全局索引,你会发现它们给出的用法仍然会强烈依赖分区键的用法。

他们使创建全局索引成为一种可选的、特殊的事情。 这样,企业在使用全球指数时就会变得非常谨慎。 自然地,全局索引的数量变得非常有限。

当全局索引的数量和使用场景受到严格限制时,上述缺点就变得不那么重要了。

用于索引选择的查询优化器

我们知道,数据库优化器的核心工作机制是:

枚举可能的执行计划

找到这些执行计划中成本最低的

比如一条SQL涉及到三张表,只考虑左深树:

所以我们可以看到,在没有全局索引或者一些中间件产品的“分布式数据库”中,它们的优化器是很弱的,大部分都是RBO,根本不需要强大的优化器,更多的优化内容其实是被一个独立的优化器。

PolarDB-X提供了一个使用代价模型的优化器:zhuanlan.zhihu.com/p/370372242。

在MySQL上实现强一致、高性能的分布式事务

要做一个透明的分布式数据库,最关键的是全局索引和全局索引所依赖的分布式事务。 中间件时代的探索告诉我们,要实现强一致性和高性能的分布式事务,必须对存储(MySQL)进行深度改造。

我们选择使用全局MVCC(TSO)+2PC(XA)的方案。

MySQL的单机MVCC包括start_timestamp(即MySQL中的trx_id)。 为了实现全局MVCC,需要做几个核心的事情:

zhuanlan.zhihu.com/p/355413022。 不要使用在节点之间交换活动事务列表或 GTM 的非常昂贵的方案。

PolarDB-X 中的事务流程:

开源分布式内存数据库_开源分布式文件系统_开源分布式存储软件

InnoDB中对记录格式的修改称为Lizard事务系统。 详情参见:developer.aliyun.com/article/795058

开源分布式内存数据库_开源分布式文件系统_开源分布式存储软件

我们还有一些其他文章介绍PolarDB-X分布式事务的实现:

有了分布式事务和全局索引,PolarDB-X正式从中间件转型为分布式数据库。

PolarDB-X透明分发

PolarDB-X实现了优秀的分布式事务和全局索引,满足了上述对全局索引的要求,实现了透明分布。

在透明分布式模式下(在CREATE DATABASE中指定mode='auto'),所有索引都是全局索引,应用程序不需要关心partition key的概念。

比如我们的建表语句和单机的MySQL是完全一样的,不需要指定partition key:

创建表订单(id bigint,buyer_id varchar(128)评论'buyer',seller_id varchar(128)评论'seller',主键(id),索引sdx(seller_id),索引bdx(buyer_id))

开源分布式文件系统_开源分布式内存数据库_开源分布式存储软件

创建全局索引也和在单机MySQL上创建二级索引的体验一致,全程在线:

在订单上创建索引 idx_seller_id (seller_id);

PolarDB-X的全局索引是强一致性的,其数据一致性体验与单机MySQL无明显差异。 它提供符合 MySQL 语义的 RC 和 RR 隔离级别。

同时,PolarDB-X在索引维护和优化器方面也做了很多工作,保证索引可以高效的创建和维护,优化器可以使用索引正确生成执行计划。

PolarDB-X的分区算法也能很好的处理索引中的热点、数据倾斜等问题。 参考:zhuanlan.zhihu.com/p/424174858

自动(透明)确定下限和手动确定上限

市面上常见的分布式数据库按照透明和手动来划分:

透明分布式数据就一定比人工好吗?

对于只提供透明使用的数据库,迁移成本会比较低,初期体验会更好。 但进入深水区后,由于不可避免地使用大量的分布式事务,在核心场景下,性能往往达不到要求(或者同样的性能需要更高的成本),有所欠缺消除分布式事务,更充分的计算下推等优化方法。

对于只提供手动使用的数据库,虽然设计好的partition key理论上可以达到最佳性能,但是使用门槛会明显提高(10%的核心表设计partition key就好了,剩下90%的核心表设计partition key就好了)非核心表也要设计分区键)。

我们认为,无论是纯透明的还是纯手工的分布式数据库,都不能很好地满足业务对成本和性能的需求。

PolarDB-X除了提供透明模式外,还全面支持分区表的语法,并提供Join Group/Table Group、分区在线变更等工具,让应用在需要极致性能的时候让事务和计算更高效. 更多下推到存储节点。

PolarDB-X是目前市场上唯一可以同时提供透明模式和手动模式的分布式数据库。 我们建议大部分场景使用透传模式,然后对核心业务场景进行压测,并使用分表语法对这些场景进行人工操作。 优化以获得最佳性能。

使用Paxos协议实现RPO=0

连接中间件的MySQL一般采用主备架构。 这种方式最大的问题就是会丢数据,时间久了甚至是不可避免的(我经常在河边走,怎么可能不把鞋弄湿)。

经过数据库圈几年的科普,基本上大家都知道需要一些一致性协议,比如Paxos、Raft等来防止数据丢失。 这些协议其实已经不是什么秘密了,甚至在数据库圈流传着“现在学校招收的学生一定会玩Paxos”的笑话。

门槛不在协议本身,而在于它与MySQL结合的稳定性和性能。 只有经过大规模的验证,踩了足够多的坑,才能获得稳定性。

PolarDB-X使用的Paxos协议来源于阿里内部的X-Paxos。 可以说,阿里内部的MySQL数据库不再主备模式,100%使用X-Paxos。 这意味着它已经经过数万个MySQL集群和各种推广的验证,具有极高的可靠性。

我们有几篇文章想写来介绍 X-Paxos:

完全兼容MySQL的Binlog协议

要想利用好MySQL生态的资源,能够利用MySQL生态的工具向下游流数据是非常重要的。 在行业中常见的解决方案中:

PolarDB-X是目前市场上唯一完全兼容MySQL Binlog协议的分布式数据库。 用户可以使用任何开源的MySQL Binlog订阅和分析工具(如Canal)连接PolarDB-X的Binlog。

开源分布式存储软件_开源分布式内存数据库_开源分布式文件系统

这极大地提高了 PolarDB-X 的可用性。 看:

未来五年

我们对未来的PolarDB-X充满了想象,希望她能成为更好的数据库。 尽管有很多不确定性,但有些事情我们会继续做。

最重要的是,我们会坚持MySQL生态,坚持以MySQL为存储节点构建分布式数据库的技术路线。 我们认为这是我们与其他分布式数据库之间非常关键的区别。 与MySQL的兼容实际上分为功能兼容和性能兼容。 使用分布式KV等技术方案可能在功能上兼容MySQL,但在性能上很难做到兼容MySQL。 MySQL是一个全功能的存储,将大量的事务和计算推送到存储节点,是分布式数据库实现高性能的关键。

业界提供全局索引的分布式数据库,全局索引的性能(写入和查询)与单机数据库中索引的性能和行为一般存在一定的差距。 缩小这个差距可以提高分布式数据库的下限。 对于PolarDB-X来说,这个差距主要来自于CN和DN(MySQL)的交互链路太长,冗余操作较多(MySQL Server层的线程连接模型、MySQL优化器、Parser等) . 我们将通过RPC协议与MySQL交互,对MySQL Server层进行细化,进一步提升PolarDB-X全局索引的性能。

自动负载均衡可以大大降低分布式数据库的使用门槛。 PolarDB-X 的一些特性(手动和自动,Join 可以下推等)与不支持这些特性的数据库相比,让这个问题变得有点额外。 难点(一滴眼泪,但我们可以解决),这块还需要一些时间打磨。

降本增效是近两年的热门话题。 PolarDB-X是关于OSS的归档能力,可以自动将历史数据dump到OSS,通过与线上数据相同的SQL接口访问。 还支持使用Spark等开源大数据工具直接分析转储的OSS文件。 详情参见:zhuanlan.zhihu.com/p/477664175。

HTAP是分布式数据库领域的热门话题,各个数据库厂商提出了各种解决方案。 但是从现有的HTAP实现来看,性能、隔离和成本处于一个比较矛盾的状态(有的数据库使用列存副本,性能还可以,但是成本高;如果做分析,性能和隔离会更差) ,这远非理想的 HTAP。 我们也会在这个领域持续投入,希望能探索出一种能够满足大部分业务场景的HTAP形态。

在数据库层面为远程多活(全球化等概念)提供更多的原生支持。 支持淘宝的站外多货,让我们的团队在这方面积累了很多经验(相信没有人比我们更了解)。 事实上,PolarDB-X是国内为数不多的实现了大规模远程多活项目(其中一个是民生级系统)的数据库之一。 我们希望将这些体验转化为数据库的原生能力,减少远程多活系统对外部组件的影响。 依赖性,使其更具普遍性。

最后,我们也会坚定的做开源,在内核层面保持商业版和开源版的代码一致性。 同时持续开发轻量级开源管控系统。

感谢您对PolarDB-X的支持,欢迎关注我们的专栏:zhihu.com/org/polardb-x