写点什么

干货分享 | MatrixOne 系统架构

作者:MatrixOrigin
  • 2022 年 10 月 07 日
    海南
  • 本文字数:8518 字

    阅读完需:约 28 分钟

干货分享 | MatrixOne系统架构

分享嘉宾:金海   矩阵起源研发 VP

讲稿整理:张德通 DataFun 志愿者


导读:随着数字化转型的深入,数据价值也愈发凸显,数据技术出现了融合的趋势,基于客户的真实痛点,矩阵起源推出了超融合 MatrixOne HSTAP 数据库。MatrixOne 使数据数据库同时具备 TP、AP 和 Streaming 三种能力,帮助客户彻底打破数据孤岛问题,成为企业智能化核心的数据基础设施。今天的分享将解析新一代超融合异构云原生数据库 MatrixOne 刚刚发布的 0.5 版本和后续版本的架构设计。


今天的介绍会围绕下面五点展开:

  • 数据存储与处理面临的挑战

  • MatrixOne 架构,各组件和设计方面的取舍

  • MatrixOne 事务相关的读写流程

  • MatrixOne 研发路线图


▌Part 1 - 数据存储与处理面临的挑战

1. 企业数字化中台组件众多

企业在做数字化转型时,常常会构建技术中台,基于 Hadoop 搭建出一整套数据处理系统。下图展示了 Hadoop 体系内常见的数据组件,如图所示组件众多,有版本、兼容性等大量细节问题需要处理,学习成本、维护成本和维护难度高。



构建和维护整个数据中台就像在搭积木,各个模块搭建起来,虽然可以工作,但整个系统很脆弱,可靠性不好。任何一个组件有问题都会导致整个系统不可用,整个系统的可维护性差,构建成本高。


2. 数据库



纵观数据库发展历程,70 年代开始关系型数据库开始出现,80 年代 OLTP 数据库经历了大规模发展,出现了 Oracle、DB2、Sybase、SQL Server;90 年代出现了 AP 型数据库,2000 年随着互联网发展,出现了 NoSQL 数据库,支持更好的横向扩展性。NoSQL 数据库对事务的支持能力不强,但其良好的可扩展性对数据存储非常友好,2000 年左右出现了一批支持 KV、文档、JSON 的 NoSQL 数据库。


2000 年开始逐渐出现了以 Hadoop 为代表的大数据系统,其中包括 Hive、Spark 等。同一时期,为解决传统数据库横向扩展能力受限问题出现了多种解决方案,一种方案是在传统 MySQL 数据库等基础之上做分库分表中间件,在中间件的基础上实现分布式事务能力;另一种方案则是以 Google Spanner 为代表的 NewSQL,此外还包括 OceanBase、TiDB、CockroachDB、YugaByte 等,其特点是底层基于 KV 引擎,上层利用 Raft、Paxos 共识协议保证日志和状态机的可靠。


从 2010 年开始,云计算得到大规模发展,数据库本身也面临着上云挑战。第一代数据库上云的问题是如何在云上部署数据库,第二代、第三代云原生数据库则会利用云上的组件,如 S3 等对象存储降低成本提升可扩展性。云原生数据库中比较有代表性的 TP 型数据库是 Aurora,AP 型数据库是 Snowflake,架构方面特征是存算分离,计算节点、存储节点可以独立扩缩容,节省用户成本,无需部署,运维简单,用户开箱即用。


大数据经过多年发展,从纯粹地用批处理解决问题变为可以用流处理做计算,对实时性要求高的场景支持得更好,与 AP 型数据库融合后大数据系统的分析能力也可以得到提升。


数据湖通常用于解决非结构化的数据,可以存储各类型数据,而数据仓库处理的是结构化的数据,两者的结合就是湖仓一体。湖仓一体比较有代表性的开源系统是 Hudi、Iceberg,非开源的有 Lakehouse。


由上面的发展可以看到,融合是大数据系统近年来的发展趋势:TP 和 AP 的融合、湖和仓的融合等等。MarixOne 正是这样的超融合数据库,类似集成了相机、电话、电子书、闹钟等功能的智能手机,具备着使用多种数据库才能实现的能力,能极大地降低数据库运维成本。


▌Part 2 - MatrixOne 架构总览

图中是 MatrixOne 的架构图,自上而下共分为 5 部分。



首先最上层的是计算层,计算层的计算节点我们称为 CN。计算节点本身可以做分析、流计算和后台任务处理。用户层面和前台业务是感知不到计算节点的后台处理任务的。


计算层下面的事务层主要节点是 DN,这些节点本身是 share nothing、可横向扩容的。每个 DN 之间和内部的数据分片是互不相交的。目前的方案是根据数据主键做数据的横向分布扩展。每个 DN 之间处理的数据范围互相没有交集,不会有冲突检测的需要。


再下层是 Log service 和 File service。DN 节点写入的数据的日志会存在 Log Service 里。Log Service 内部使用 Multi-Raft,构建可靠的存储状态机。异步的 compaction 任务把写入的日志合并后写入 File Service。File Service 是一个通用的接口,底层可对接本地磁盘、NFS、S3、HDFS 等多种数据存储系统。


HA Keeper 组件不是大数据里常用的 Zookeeper,而是一个集中式的集群管理组件。目前的实现方案是用单 Raft 组实现。HA Keeper 维护的是计算集群、DN 集群、Log Service 集群的状态和可靠性。HA Keeper 发现集群内节点挂掉后会把节点拉起。

1. File Service

MatrixOne 对自身的预期是可支持云原生和私有化部署,无论云上还是私有化全部使用一套方案进行部署。在私有化环境下,用户的实际存储环境多种多样,用户可能选择使用 HDFS、Ceph 等等做存储。云原生场景下也有多种选择,S3 兼容的协议,阿里云 OSS 等。


在此背景下我们对存储进行了通用抽象,这一服务即 File Service,作为存储接口提供给 DN 节点和 CN 节点进行数据交互。同时,File Service 本身也承担了数据缓存的工作。

2. Log Service

Log Service 是一个 Multi-Raft 组。由于存储的是 Log tail,数据量不大。但我们对 Log Service 的吞吐量要求非常高。因此,在部署时候需要给 Log Service 配置更好的硬件设备,如硬盘需要用 SSD 盘。

3. Transaction DN 节点

每个 DN 节点是 shared-nothing 的,每个 DN 节点之间互相访问的数据是不重叠的。目前版本 DN 组件的数据划分使用对主键做哈希的方式实现,不使用 range 的方式实现,因为我们认为哈希方式会让分布更加均匀。


DN 节点的横向扩容难度比 CN 节点的横向扩容大,传统的 NewSQL 扩容节点可以利用 Raft 组的特性、加减副本即可完成扩容;但 DN 节点近期几个 Release 版本暂时没有计划 DN 的横向扩容,后续版本会增加扩容方面的优化。

4. 计算节点 CN

MatrixOne 是存算分离的架构,计算节点 CN 节点的横向扩展能力很强,可以任意地扩缩容。


CN 节点除了前台查询任务,还处理流任务和后台任务。后台任务包括异步的 Compaction 任务,本身会对数据进行修改,与前台任务数据会发生冲突,这些冲突需要被检测和处理。


后台任务方案由 DN 节点发起。DN 节点维护状态机,状态机发现节点后发起异步任务给 CN 节点调起后台任务。这个过程不需要很高可靠性,异步后台任务并不需要很高的实时响应能力和幂等性。

5. HA Keeper

HA Keeper 维护了集群各节点的状态,和集群内各节点保持心跳,节点挂到后把节点拉起;此外 HA Keeper 还和外部 K8S 资源池交互,把新增节点的上下文建立起来。HA Keeper 是一个单 Raft 组的可靠集群,本身并发性不高,只能承载不高的心跳频率。


▌Part 3 - MatrixOne 事务相关的读写流程

1.事务流程

Matrixone 使用的两阶段提交(2PC)实现事务和目前 NewSQL 方案略有区别。具体写入流程如下:



客户端使用 write 接口写入数据,请求到达 CN 节点后在 CN 节点上保存事务的读写空间 workspace。数据只有到达 DN 节点才开始冲突检测。


一个事务从 begin 到 commit 中间发生的数据交互都会存储在 CN 节点的 workspace 上,一旦客户端发起 commit,CN 节点会进行两阶段提交把数据推到 DN 节点。Workspace 数据可能分布在多个 DN 节点上,因此我们设计了 DN 节点内部两个阶段的处理流程:第一阶段是 prepare,第二阶段 commit。


为了保证两个阶段本身的可靠性,我们保证多个 DN 节点里选取一个作为 coordinator,在一些系统中这个角色也被称作 transaction record。第一个 DN 节点我们会做 transaction commit,并把所有 transaction 参与者都记录在 transaction coordinator 里。


发生事务时,首先要把 prepare log 写入 Log service 进行持久化,包括 transaction 的 commit 信息、DN 上的 prepare 信息等都做持久化存储。prepare 的事务信息会返回给 CN,CN 节点收到事务参与者的 response 即整个事务成功,随后返回用户提交已经成功;或在 rollback 后再返回用户。


两阶段事务是一个异步的过程,DN 节点 commit 过程是与 prepare 后返回给用户提交已经成功是异步进行的。两阶段事务具一些特殊性:首先 workspace 存储在 CN 节点上,冲突检测在 DN 节点上进行;第二个特点是分布式事务使用 Clock SI 方式分配 timestamp。


2.时钟



Clock SI 本身定义如上图红框圈中内容。任何一个事务会开启一个一致性快照,快照的开始时间是由一个快照时间戳确定的,在这个时间戳以前,所有已经 commit 的事务在这个快照里都可见。提交的时间戳是全序的。如果发生并发写写冲突,事务会被取消。


Clock SI 主要解决了没有中心节点情况下的时间戳分发这一问题,也就是使用每个节点自己的时间戳。但节点和节点之间存在始终时钟漂移的问题,时钟漂移会面临两个错误错误:



第一个错误是快照不可用问题,左侧 Fig.1 展示了处在不同节点上的 P1、P2 两个事务参与者,他们之间存在时钟漂移,这会导致 P2 到达 t 之前快照不可用的问题。


第二个错误是 Fig.2 展示的,T2 如果在 T1 提交时候读,拿到的数据需要等到 T1 提交完成后才能读到 T1 提交后的数据,不等待则读不到数据快照。


对于第二个错误,Clock SI 使用上图中的算法 1 解决这两个问题。当 T.SnapshotTime 超过了当前提交时间戳才能读到数据,否则进行等待;也就是当前如果有事务在做 prepare 和 commit,需要等待 prepare 和 commit 都完成后才可以进行冲突检测、做提交。


MatrixOne 把 Clocks SI 和 HLC 结合,HLC 是混合逻辑时钟,两个事务参与者发生时钟漂移时使用混合逻辑时钟校准,从而解决第一个错误。


3. 读

对数据一致性要求较高的读请求,读请求到 CN 节点后需要从 DN 拉取数据的最新分布,DN 把最新的元数据和 meta 都返回给 CN 节点。CN 节点根据这些信息从 File Service 接口拉取到真正的数据。



MatrixOne 使用单一的列存存储数据,每个 column 的 block 和 segment 的树形结构和 bloom filter、minmax index 等信息都保存在 meta、index zone 里,所有数据写入都是 append only 的,不论更新、插入还是删除都只是增加新文件。查询时用 Merge on read 的方式做合并。


DN 内保存最新的 meta,使用树形结构保存在 DN 内。查询的时候,CN 会问 DN 要当前需要的快照和 Log tail。CN 根据快照里记录的对 SQL 进行裁剪。比如做 SQL 查询时,可用 bloom filter 做 runtime filter。使得,真正需要读取进行计算的数据量比较小。


此外,DN 节点会返回 Log tail 数据给 CN 节点,这部分日志数据相对较小,因此问题不大。


对于 TP 类查询,CN 在拿到最新的数据后即可做一致性读。而 AP 类查询对数据一致性要求更低,可以使用 CN 内存储的 meta 读取,对 DN 负载压力较小,可以承载很高吞吐量。


4. 异步 compaction

我们既可以用 CN 扫描数据决定是否做 compaction,也可以由 DN 节点判断是否进行 compaction。下图展示了使用 DN 做 compaction 的操作流程。



当 DN 节点发现数据删除过多,数据零散,这时会进行数据合并。数据合并时触发一个专用的用来做 compaction 节点跑合并,CN 节点会把要发生 compaction 的数据进行收集,在 CN 节点内合并后提交。


Compaction 会对数据产生产生修改,这个过程本身也是一个事务,会向 DN 提交数据并进行数据检测。


Compaction 过程中修改的数据,前台任务也有可能修改了这部分数据,此时可能发生写写冲突,发生写写冲突时会 abort 后台 compaction。此时要重跑 compaction,独立的 CN 节点跑 compaction 任务也不会对用户体验造成影响。


5. Streaming 方案实现计划

目前由两种方案做 streaming,一种是数据发生修改,根据上一次产生的 snapshot 和当前的 snapshot 产生的 delta snapshot 推到 CN 节点上,CN 节点本身根据 streaming 任务生成 DAG 图,在 DAG 图上做增量计算。增量计算也会取得上一次查询结果,以此为依据做增量计算。



最终查询结果是上图中的 delta 查询结果和基础查询结果的组合。存储中间结果的部分用推的模式。


另一个方式是定期地、在用户做 streaming 查询时从 CN 节点拉取 base result、拉取 delta snapshot,再做增量查询。查询结束后把最新的 base result 存储到 S3、HDFS 等可靠存储上,下次做增量计算时可以用到存储的 base result。


▌Part 4 - MatrixOne 研发路线图

刚刚发布的 MatrixOne 0.5 版本实现了列存带事务的分析引擎,第三季度即将发布的 0.6 版 MatrixOne 将支持分布式事务,TPC-H 和 TPC-C 性能都有大幅提升。



2022 年底计划发布的 0.7 版本将支持 streaming,也会支持更多高级 SQL、window function 等。0.7 版本 MatrixOne 计划上线云服务。


▌Part 5 - 精彩 Q&A 实录

Q1. 扩容是冷扩容还是热扩容?

A:我们期望实现热扩容。但会先支持冷扩容,冷扩容指的是在线的事务先 abort,执行扩容,扩容完毕后再重新开启事务。整个过程速度很快,因为只扩容 DN 节点和对应的 Log tail 状态机。Log tail 存储的数据量少,扩容快。我们计划实现热扩容,可能会以追日志的方式实现热扩容。

Q2. 元数据没有存 Zookeeper?

A:元数据存储在 HA Keeper。表结构我们成为 Catalog。每个表数据索引的位置、数据的多个版本被认为是元数据,也叫做 meta。HA Keeper 本身存储当前集群是否挂掉,和每个 DN 分区负责的哈希桶。Catalog 表信息存储在可靠存储 File Service 上,最新的可靠元数据信息是存储在 Log Service 上。

Q3. CN 层和存储层是 Share Disk 架构吗,这样是否在扫描数据的时候影响性能?

A:File Service 存储数据,访问数据也是 CN 节点通过 File Service 拉取数据,DN 节点处理数据只做事务的冲突检测。DN 节点冲突检测时访问数据有限,会先过滤,不会全量访问数据。且冲突检测通常只存在于一两个分片上。CN 在进行 Scan 时也会对谓词做下推,Join 时用 Key 决定访问数据范围,没有 where 条件的 select * from table 的请求对数据库性能影响很大。

CN 节点对 Scan 类查询做谓词下推,最后 CN 节点真正要访问的数据范围有限,使用 zone map 过滤后确定部分数据。Join 时维度表相对事实表更小,对性能影响不大;事实表通过维度表构建好 Hash Table,根据 hash key 建立 block、再下到事实表,用 bloom filter 过滤。最终访问的数据块也很小,减小数据访问的范围。

元数据、zone map、bloom filter 这类索引信息都会在 CN 节点上有缓存。

Q4. DN 内部的副本复制也用 raft 吗?

A: DN 在现在的方案内没有副本,意味重启一个 DN 时,需要从 log service 回放日志来恢复 DN 的状态机,此时当前 DN 不可用。我们可以把 DN 做成主备和三副本的形式,从 log service 拉取 log tail,现在使用的 DN 没有 stand by 节点。

Q5. Clock SI 里时钟方案相比 HLC 和 TSO 的优势是?

A: TSO 有中心节点,HLC 每次访问时虽然需要同步时钟,但同步可以发生在节点和节点之间。ClockSI 使用本地时钟,延迟低,但节点之间可能存在时钟漂移问题。

Q6. 读取会不会随着 del 和 update 增多性能下降,会有异步的合并吗?

A: MatrixOne 是后台任务异步合并,而大量 delete 和 update 带来的垃圾数据多问题,会通过后台合并任务 merge 掉这部分数据而得到解决。

Q7. 纯列存是指内存和磁盘都是列存吗?查询时会区分 TP 类查询还是 ap 类查询吗?

A: 纯列存是磁盘和内存都是列存,查询时候会通过 optimizer 区分是 AP 还是 TP。

Q8. 资源隔离有什么考虑?

A: 首先是 TP 和 AP 之间的资源隔离,TP 和 AP 的 CN 节点分开。根据 AP 查询的一致性要求高低决定从 CN、DN 还是 File service 服务拉取元数据信息。

其次是租户之间的资源隔离。目前的方案是 VIP 用户部署单独的一套 K8s deployment,普通用户根据 schema 进行资源隔离。后续可能会实现 cgroup 类似的方式限制租户隔离。

Q9. DN 有开源的原型吗?

A: MatrixOne 实现比较偏向 NewSQL,DN 也是 share nothing 实现的。我们参考过 duckdb,但 duckdb 的 update 和 delete 是用 version chain 方式实现的,0.6 版本后我们不再使用这一方案。

Q10.有考虑过不基于类似 lsm 的思想做存储层,而是采用 copy on write 或者类似 kudu 的 delta store 又或者 adb 采用的 delta and insert 方案吗?

A: MatrixOne 现在的方式也是 LSM Tree 的模式。LSM 可以认为是分层的架构,以 RokcsDB 为例,它一共 7 层,最底层一定是全序的。MatrixOne 为了避免写放大,没有全序的层,每层之间都有 overlap。

Copy on write 的实现方式存在一些问题,本质上对原有的数据块进行了修改、用新数据块替代了原有数据块,对元数据的修改比较复杂。LSM Tree 是 append only 的,对元数据修改也是 append only 的,对于过去数据的 compaction 也是 append only 解决的。

MatixOne 就是 delta insert 的实现,元数据管理复杂度大大降低。

Q11. 流处理和分布式事务处理的结合,是否考虑过采用类似 iceberg 的元数据管理的思想?

A: Iceberg 的元数据管理和我们的管理方式没有太多区别,但 Iceberg 把元数据都存储在 S3 上,而 MatrixOne 有 DN 加 log service 做元数据缓存,性能更好。

我们认为流是一个常见的后台常驻任务,任务随时根据数据源变化后推送或拉取新的数据执行分布式计算任务。分布式事务需要把流事务处理完才能返回成功,整个链条很长,返回更慢,这里就是一个取舍:流处理保证一致性还是让整个流程更快结束。我这里认为流处理和一致性不需要做强一致性,事务写完成后离开用流处理引起读,此时能拿到最新的数据,处理结束后整个流程结束,把事务分为两步进行。

Q12. AP 相比主流的 OLAP 引擎,如 Clickhouse,性能如何?

A: 我们期望 MatrixOne 能和 Clickhouse 性能相媲美,但需要看具体场景具体分析。Clickhouse 是存储计算不分离的,数据压缩、merge tree 全序排列等特性会让 Clickhouse 更快;但 MatrixOne 的存算分离,非全序排列等特性也是 Clickhouse 无法比较的。Clickhouse 的 delete update 是不能立刻可见的,但 Matrixone 是立刻可见的,这就是全序排列和非全序排列的取舍。存储全序排列主要影响主键,非主键的零散数据对数据压缩影响不大,因此 AP 计算引擎比较起来要具体场景具体分析,我们会做持续优化。

Q13. 性能怎样同时兼容 AP 的大数据量和 TP 的高并发实时更新的?

A: AP 和 TP 是用不同计算引擎做的。AP 是的大数据量通常是查询的数据量大、不是写入的数据量大。为例支持 AP 的大查询量,数据写道 S3 上后最终提交时只由 CN 节点提交一次数据到 DN 上,DN 上加载数据做冲突检测。CN 上加载数据时已经做过一部分冲突检测,在对从 S3 上加载来的数据和 logtail 之间做检测。这个实现可以支持大批量加载。TP 高并发和 AP 大读数据量可以兼容。

如果不需要一致性读 AP 可以 CN 直接读 S3,不会影响 TP 性能;而需要一致性读的情况下,需要从 DN 读数据,DN 上是高并发的实时更新的数据,此时 DN 会成为瓶颈,需要扩容 DN 节点。DN 上拿到的是 logtail 和最新的元数据,CN 上已有的快照元数据和 DN 上最新的快照元数据的不同也是很小,可以按批取这些数据,能极大地利用网络传输吞吐。

Q14. AP 和 TP 底层是否有不同的存储结构?

A: 是一样的结构,都是存储成列存格式。

Q15. AP、TP 怎么调度?优化器针对 AP,TP,streaming 融合做了什么修改?

A: 优化器绑定时可以拿到元数据和索引,通过索引构建直方图,能够判定数据分布,判断数据量的大小。 由此判别是 TP 还是 AP 查询,随后把请求转发到 AP 或 TP 专用的 CN 节点上进行处理。

针对 Streaming 我们目前还在规划中。

16. 在数据新鲜度上,HSTAP 采取了哪些措施?

A: 每次查询都到 DN 节点上读的方式一定是数据最新鲜的方式,TP 数据只要写下去一致性读一定能读到最新数据,AP 和 TP 使用一套列存,不存在数据同步等等延迟问题。

Q17. 流处理如何保证最终一致性?

A: 一旦发生了更新,会把更新的 delta snapshot 推到流数据计算服务上,经过计算产生流处理结果;或是在查询段流数据查询直接查,查到的数据是具备一致性的。

Q18. 写流程中,第 3 步会客户端响应后,第 4 步写 commit log,这是否有问题?

A: 只要 prepare 全部完成,事务的提交已经成功,commit 只是修改 commit 的时间戳。每一个事务参与者拿到事务时间戳有前有后,最后 commit 的时间戳需要是 prepare 的时间戳中最大的。这时候异步写不会有问题。

Transaction coordinator 记录了事务的参与者,一旦事务中途挂掉,重新启动后会读取 transaction coordinator 内的 log service 的数据,这部分数据是可靠的。通过这个数据即可知道事务参与者,并检这些参与者的事务是否提交,没提交的话就把整个事务 abort,提交了就不会有任何问题。

Q19. DN 上的元数据如何做到?有何优化处理

A: Table 到 column 下每个 segment 其实是一个元数据数,可以理解为元数据存储本身也是一个元数据数据库。目前我们用 LSM tree 方式实现,内存里有状态机,写的具体内容是每一条元数据的状态机修改的日志。写完后内存的状态机会定期地刷到 S3 等可靠存储上。

这种实现可以比较方便地做数据的 delta,CN 来的查询单位一定是有事务构成的 snapshot,snapshot 是有每个事务的 commit 构成,每个 commit 也对应着一个数据元的修改。查询实际上是以 snapshot 或者 commit 为单位的,元数据修改所产生的 delta 可以拿到 CN 上做回放,CN 就能拿到最新元数据。

Q20. OB 和 MatrixOne 事务处理机制一样吗?

A: 大的流程都是 2PC,细节上区别不少。比如 OB 时间戳使用 TSO,MatrixOne 使用的是 Clock SI 配合 HLC 方式实现。


MatrixOne 公司矩阵起源专注于构建超融合异构云原生数据库,为用户提供极简、高效的数据系统工具和服务,让数据应用和运维工作非常简洁的同时保证极值性能。帮助用户和企业简单、敏捷高效地拥抱数据价值,降低企业数字化转型门槛。


矩阵起源全面拥抱开源生态,以开源开放的方式探索数字化道路。矩阵起源有多个行业的数字化转型最佳实践。


欢迎扫码加入 MatrixOne 社群参与讨论:

添加 MO 小助手微信 → ID:MatrixOrigin001,加入 MatrixOne 社群参与讨论!

官网:matrixorigin.cn

源码:github.com/matrixorigin/matrixone

Slack:matrixoneworkspace.slack.com

知乎 | CSDN | 墨天轮 | OSCHINA | SegmentFault:MatrixOrigin


发布于: 12 小时前阅读数: 7
用户头像

MatrixOrigin

关注

还未添加个人签名 2021.12.06 加入

一个以技术创新和用户价值为核心的基础软件技术公司。

评论

发布
暂无评论
干货分享 | MatrixOne系统架构_MatrixOrigin_MatrixOrigin_InfoQ写作社区