HTAP 一直都是数据库领域的热门技术话题,在 3 月 26 日的 DataFun 大数据存储峰会上,矩阵起源 CTO 张颖峰首次对外亮相介绍了整个数据库领域实现 HTAP 的五种技术路线,以及矩阵起源的 MatrixOne 项目的实现思路。
MatrixOne超融合HTAP数据库的存储引擎设计
在数据库几十年的发展历程中,有两种最主流的数据处理负载,OLTP(后文简称 TP)联机事务处理(On-Line Transaction Processing)和 OLAP(后文简称 AP)联机实时分析(On-Line Analytical Processing)。前者侧重于交易的处理过程,比如银行的转账,网站订单等,后者侧重于数据分析,比如大量数据统计与展示等。这两类负载在很长的一段时间内都是由不同的数据库产品来满足的。但是在实际的使用场景中,往往两类需求都需要被满足,因此用户希望有一个单一数据库可以既支持事务处理,也支持数据分析。
2014 年, Gartner 在《混合事务/分析处理促进重大商业创新》报告中用 HTAP(Hybrid Transaction and Analytical Process,混合事务和分析处理)一词描述新型的应用程序框架,以打破 TP 和 AP 之间的隔阂,既可以应用于事务型数据库场景,亦可以应用于分析型数据库场景。HTAP 一词从此被业界熟知。
图:Gartner 对 HTAP 的描述
(图片来源:Gartner)
HTAP 架构看起来对用户使用非常友好,对简化企业的复杂大数据结构将起到非常关键的作用。但是 HTAP 的实现并不是一件容易的事情,TP 与 AP 在很多方面都存在着巨大的矛盾。如下表所示,比如在数据插入方面,TP 数据库一般都是插入即可见,每行数据插入之后马上就可以查询到,但是 AP 就不一定能做到这点。在数据更新方面,对 TP 来说是个必备功能,但是让 AP 支持单行级别的 UPDATE 是一个非常有挑战的问题。再比如在一些经典关系模型中非常重要的事务、完整性约束、次级索引等特性来说,AP 数据库都会支持的相对比较弱。而在 AP 比较擅长的复杂查询和大量数据查询能力上来说,又是很多 TP 数据库的弱项。
图:OLTP 与 OLAP 的矛盾
这其中有很大程度上由于系统的应用定位不同,导致了设计上的差异。比如在次级索引上,TP 数据库的索引设计非常直接,比如 Hash Index, Bitmap Index, B-Tree 等,这些次级索引本质上是为了满足某种范围内的少量数据访问的 Range Query,去帮助查询加速。
但是对 AP 来说,我们往往更看重扫描的性能,所以说绝大多数次级索引都会产生随机 IO 和大的构建开销,因此做多索引的意义有限,一般 AP 数据库只会采用像 Zonemap,Sparse index 这样的简单索引。
我们可以看到要把 TP 与 AP 融合成一个 HTAP 系统是有一些本质的矛盾点的。那针对这些矛盾点,学术界已经做过相当深入的研究。比如 OSDI 2021 会议上的“Retrofitting High Availability Mechanism to Tame Hybrid Transaction/Analytical Processing”这篇文章就针对数据实时性与性能影响程度的矛盾点做了深入研究。
如下图所示,x 轴是数据实时性,即一个数据从 TP 系统写入到 AP 系统可读到的延时,y 轴是 TP 能力的下降程度,即在 TP 与 AP 查询同时进行的时候系统的性能下降程度。
图:数据实时性与性能影响程度的 Tradeoff
(图片来源:https://www.usenix.org/system/files/osdi21-shen.pdf)
我们可以看到 HTAP 的实现本质上是一种系统级的 Tradeoff 取舍,在不同的维度和重点之间找到一条合理的组合。基于学术界和工业界多年的研究和实践,我们对 HTAP 的五种技术路线做了一个详细的归纳与对比。
首先,我们将 HTAP 的五条技术路线分成两大类:第一大类是将现有的 TP 与 AP 做一个包装,通过一些中间件的方式将它们连接起来再做一个封装,本质上仍然是两套系统。第二大类就是融合,抛弃现有的 TP 与 AP 独立架构,从底层存储开始就将 TP 与 AP 的引擎融合起来,形成一套系统。
图:HTAP 的五条技术路线
路线一本质上是一种中台,就是我们把现有的 TP 和 AP 通过 ETL 连接起来。这里普遍的一种做法是通过一个流式 join 的方式将多张 TP 表连成一张 AP 宽表。这个流式 join 对大数据社区来讲有很多的选型,比如 Debezium 作为 CDC 工具,Kafka 消息队列以及 Flink 流式计算引擎等。在这样的系统中往往至少需要这三种东西,才能把数据从 TP 合并到 AP 里去。因此这种路线,它本质上是一种中台的构型。它的缺点就是组件太多,成本非常高,优点是在技术实现上非常容易,我们只需要在前端实现一个统一的 Proxy,通过它分析我们 SQL 的请求是 TP 型的还是 AP 型的,然后将请求路由到不同的引擎上即可。即使不实现这个 SQL Proxy 的话,也可以由中台的开发人员从业务逻辑入手来拆解我们的请求应该怎么去处理,其实这也是近些年互联网和传统企业建设大数据平台或者数据中台的一种普遍做法。另外,在使用场景上来说,路线一的应用范围是最广的,因为它能将多个 TP 的表连接成一张宽表,这种用法是 HTAP 使用场景中最普遍的一种用法。
路线二我们将之称之为广义 MQ 模式,事实上它与路线一的模式比较接近。它与路线一的区别就是通过将 TP 的日志复制到独立的 AP 引擎来实现两套系统的连接,从存储和计算来讲他们仍然是独立的两套系统。而广义的 MQ 就是有一定创新性的连接方式,比如业界目前比较熟悉的 TiDB 中采用的就是这条路线,他们采用 Raft Learner,这比路线一在产品的完整性,实时性以及数据的一致性上有了质的提高。但是路线二在使用场景上相比路线一有一个明显的限制,由于该路线的做法是将一个 TP 数据库的日志通过广义 MQ 传到 AP 的存储引擎里做回放,那就只能是一张 TP 表对应一张 AP 表,但是我们几乎所有的 AP 使用场景的时候都是需要几十甚至上百张 TP 表 join 成一张很大的宽表,然后再去进行数据探索分析等等。因此这条路线缺了一个很关键组件就是 Stream 处理。这里所谓的 Stream 处理是指必须具备完整的 Stream SQL 能力,特别 Stream Join 能力,它能把多张 TP 的表实时增量的连接成一张宽表,缺乏这个能力会导致这条路线的使用场景比较局限。
路线三四五与前面两条路线不同的是,是采用融合的形式来实现 HTAP,也就是采用一套存储与计算引擎既做 TP 也做 AP。融合型路线的特点是实时性更加受到重视,也就是希望达到更快的数据插入即可见性,同时也会极大的降低冗余存储和组件运维成本。
路线三我们称之为多副本融合模式,这种模式目前停留在学术界,并没有工程化的产品出现。它的核心思考是利用现在新型数据库系统都是分布式高可用的特点,而分布式的实现机制又绝大部分都是靠复制状态机(RSM),那么复制状态机中所需要的三个数据副本没有必要全部采用一种引擎。我们可以将两个副本用 TP 的行存存储,一个副本用 AP 列存存储。三个副本的节点都参与复制状态机的投票。这个方式有个缺点就是,AP 的列存本身的实现机制与 TP 的行存实现机制有较大差别,如果 AP 的列存更新性能不佳的话(这是列存的主要难点之一),就会影响分布式共识的性能,因此会拖慢整个系统性能。当然,如果列存解决了更新的挑战,这不失为一个好的方案。
路线四相比路线三进一步整合,在引擎内部都会有两份存储,行存和列存各一份,行列之间做自动转换。计算引擎这块也做好了融合,查询优化器会根据查询自己去选择 SQL 请求应该走哪条路线。这条路线是传统数据库大厂用的比较多的路线,包括 SQL Server 和 Oracle。
图:路线四产品代表——SQL Server
SQL Server 是路线四的典型代表,它将列存看作行存的索引,行存保存全量数据,放在内存中,基于 Bw-Tree 实现。列存包括两部分 Delta + Main,Delta 存放刚从行存转换过来的列存, Main 是一个 Append Only 的列存引擎。从行到列转换的时候,会分配一个行号 RowID,这个 RowID 行号是要会写回行存的 in-memory table 里去的。所以在列存发生更新的时候,它回写的行号 RowID 会跟行存本身的事务产生一些冲突,包括在 GC 的时候也会产生竞争,对 TP 性能产生一定影响。
图:路线四产品代表——Oracle
另外一个路线四的代表就是 Oracle。Oracle 采用堆表来存全量数据,堆表其实就是堆文件。而不管是行存还是列存,在 Oracle 看来,都是索引。以堆表的方式存放数据,这时行存和列存其实就都是缓存,特别是行存的这种针对主键的索引和次级索引,都是以缓存的形式去放的。而对列存也是一样的,针对某一列或者某几列,可以去指定是否存在列存里。国内的比如 PolarDB 其实也是以类似的思路实现——将列存看作索引放到内存或者缓存。
路线五是融合型路线中融合程度最高的,没有行存和列存分别存储的区分,就是完全靠一个存储引擎同时处理 TP 和 AP。其中典型的代表如 SingleStore 与 HANA。
图:路线五产品代表——SingleStore
SingleStore 的做法是将增量数据放在内存里,用行存的格式存储,而列存用于持久化,可以存在本地文件系统里,也可以放到云原生的存储里面去。增量行存数据到列存的转化是自动完成的,整个系统只有一份存储。由于行存对分析来说有一定的性能影响,所以 SingleStore 就将行存存放在内存里,不至于因为针对这部分数据的查询影响整体的吞吐量。
图:路线五产品代表——HANA
HANA 最早是一个内存数据库,但是在后来的发展中也有了自己的持久化引擎。HANA 也是一个 Delta+Main 结构。Delta 有两级,L1 Delta 采用面向写优化的行存结构,L2 Delta 是一个 Append Only 列存,Main 存放读优化的列存结构。当行存从内存中进行落盘时,会触发 Compaction 行为,通过合并不断去增加写放大,来满足对读的一些优化。HANA 整体上看就是用一个存储(主要是列存)去服务 TP 和 AP 的系统。
HTAP 是一个非常复杂的工程架构,其中对不同的指标看重程度会导致系统的不同 Tradeoff。那究竟如何评估和衡量一个 HTAP 系统的好坏呢?这里我们将上述五种路线做了一个全面的对比,从 6 个维度来评价和衡量。
运维开销:路线一本质上是个中台,需要维护大量的组件和 pipeline,运维开销比较大,其他四种路线都是将功能融合到一个数据库中,不管是封装的还是融合的,运维开销都比较低。
一致性:路线一其实基本不保证一致性,因为会涉及到很多跨数据库组件的复杂交互,甚至很容易出现一些数据不一致的情况。那么路线二到五,理论上都可以在提供 HTAP 能力的基础上保证事务的一致性。而其中路线二在提供事务一致性的时候可能会牺牲一定的性能,由于其通过 Raft Learner 去做连接,如果要在保证强一致的时候去从列存获取数据,这样会对 AP 性能产生一定的影响。如果放弃一致性保障性能就可以做到比较高。
时效性:对后三条融合型路线来说,都可以做得到实时。而前两条路线延时相对比较高,尤其第一种很多都会达到分钟级甚至以上的延时。
混合负载隔离性:这个指标与性能密切相关,路线一和路线二理论上性能是最好的,因为他们本质上就是分开的两套系统,所以天然就是隔离的。但是从路线三开始就没有那么强的隔离性,路线三和路线四都只能做到存储隔离,很难或者无法做到计算隔离。路线五由于是单引擎,因此本身就不存在隔离机制。
使用成本:路线一毫无疑问是成本最高的,因为有多套系统和多份存储。路线二的话也是相对较高的,因为两套系统包含两套计算和两套存储,每套存储还需要单独再实现高可用副本,冗余相当多。路线三四都可以做到一套系统两份存储但是共用一套多副本机制,因此存储冗余度会更好。开销最小的是路线五,一套系统一份存储一套靠可用机制就可以满足 TP 和 AP。
使用场景:只有路线一的使用场景是最多的,因为当前 80%以上的 AP 用户都是采用生成宽表的用法,根据宽表自己去做数据探索或者交互式分析。而路线二到五的场景会侧重于实时分析,对实时性要求更高的场景,这种目前仍然是相对比较小众的场景。
MatrixOne 的定位是超融合异构云原生数据库, MatrixOne 希望通过一套比较简洁 one-size-fits-most 的架构,能提供一套统一的满足大部分场景数据处理需求的平台,将复杂性包含在系统内部,让用户能够高效快速的处理和应用数据。MatrixOne 也将将极简易用作为重要的设计准则,尤其对于 IT 能力并不太强的传统行业而言,MatrixOne 希望将大数据系统设计的与 MySQL 一样简单。关于 MatrixOne 的整体产品和技术理念可以参考之前的一系列文章《昂贵、复杂、低效... 中小型企业如何打破大数据技术栈困境》, 《MatrixOne技术架构详解》。
基于这两个设计思想,MatrixOne 采用了一种路线一与路线五的结合模式来设计我们的架构,我们称之为 HSTAP(Hybrid Streaming/Transaction/Analytical Processing), 除了满足 TP 与 AP 融合以外,通过增加流的能力,来同时满足应用场景的丰富度。如下图所示,MatrixOne 的架构前端有统一的 SQL 层,包含了 SQL 的计算引擎。中间层这块是我们的分布式框架 MatrixCube,也是基于复制状态机实现的,它目前基于 Raft 去管理存储引擎。
图:MatrixOne 的 HSTAP 愿景
存储层正在设计一套 TAE(Transactional Analytical Engine)引擎,其核心与上文中路线五一致,都是采用一套存储引擎来同时满足 TP 与 AP。而我们所采用的存储引擎是基于列存所构建,原因是我们对 TAE 的定位是面向 TP 优化的 AP 引擎,或者是带事务一致性的 AP 引擎,因此基于列存构建可以满足 AP 的高性能要求。在 MatrixOne 去年年底 release 的 0.2 版本中,我们已经完整的验证了列存与 Raft 协议的结合的可行性,同时性能与成熟的 AP 数据库相比不相上下,我们将其称之为 AOE 引擎(Append Only Engine),而 TAE 引擎将由 AOE 进化而来。另外 MatrixOne 将会设计自己的流引擎(Streaming Engine),这里我们会结合路线一中重要的 Stream join 能力,以构建系统内部可以将多表快速连接成一张宽表的能力。这个能力是绝大多数 AP 使用场景中都会用到的能力。
基于这样一套架构,MatrixOne 将会以相对统一的构型实现 HSTAP,既能满足融合型路线中的高实时性,低存储冗余度,强一致,同时又能兼顾路线一中对应用场景的全面覆盖程度,以及好的负载隔离。目前 MatrixOne 的 TAE 引擎与流引擎都在设计中。根据我们的路线图,今年 7 月份我们将推出一个单机版的 TAE 引擎,预计到 10 月份将完成将分布式事务框架与 TAE 引擎的结合,形成分布式 TAE 能力,而到年底的时候,预计将有一个初步的流引擎面世,届时将会是一个完整的 HSTAP 版本。顺便提及一下,基于复制状态机的存储引擎管理架构,也会发生大的变化,以更好应对云原生架构。
MatrixOne 也是一个完全开源的社区驱动型的项目,欢迎感兴趣的开发者和数据库用户关注和贡献。
官网:matrixorigin.cn
源码:github.com/matrixorigin/matrixone
Slack:matrixoneworkspace.slack.com
知乎 | CSDN | 墨天轮 | OSCHINA | InfoQ:MatrixOrigin