乐趣区

关于数据库:读论文-F1-Lightning-HTAP-as-a-Service

作者:马晓宇

论文公布之后曾经有一段时间了,之前提到的这篇文章因为种种原因也是欠了有些日子,道歉了大家。

上次说过,这次 VLDB 有好些篇都是 HTAP(Hybrid Transactional / Analytical Processing)主题。自打 2014 年 Gartner 提出这个说法,因为针对交易数据的实时剖析需要越来越多,这些年来 HTAP 曾经变成一个热词。除了 PingCAP 的一篇,还有 IBM 的 PingCAP 的一篇 Replication at the Speed of Change – a Fast, Scalable Replication Solution for Near Real-Time HTAP Processing,和明天要说 Google F1 团队的 Lightning 论文。甚至其余一些由非 TP 角度切入的零碎也向 HTAP 的含糊地带演进,例如阿里的 Hologres 论文以及 Databricks 的 PingCAP 的一篇 Delta Lake 论文。

因为其超前的数据量和用户场景,Google 在诸多畛域始终是明灯一样的存在。尽管 F1 近期两篇论文并没有到眼前一亮的境地,然而狗记的文章还是会受到有数关注,这次就和大家一起读一读这篇,并且联合之前的 TiDB 论文做一些比照。实际上,咱们感觉仅就 HTAP 的架构设计而言,咱们兼顾了 F1 Lightning 的简直所有设计劣势,并且能提供更多。

论文在 Related Work 章节援用了一篇 IBM Research 的 PingCAP 的一篇 HTAP Survey 短文,总结的挺有意思的,这里举荐大家看下,咱们团队写论文的时候,也是通过这篇按图索骥来调研其他人成绩的。

现有的 HTAP 零碎被分为两种设计类型

  1. 繁多零碎承载 OLTP 和 OLAP(Single System for OLTP and OLAP)
  2. 拆散的 TP 与 AP 零碎(Separate OLTP and OLAP System)

市面上不少从零开始的 HTAP 我的项目都是由繁多整合系统动手,因为从零开始,他们能够做更紧耦合的设计也没有太多历史包袱。再细分的话,这里还有抉择繁多存储引擎或者应用混合行列引擎的不同设计,而行列混合的设计显然更具性能劣势。值得一提的是,文中没有讲到一个很要害的点,就是相互烦扰的问题,单零碎的设计很容易造成 AP 作业烦扰 TP,这对一个须要在庄重场景下运作的 HTAP 零碎其实是无法忍受的。

拆散零碎的益处是能够独自针对 TP 和 AP 进行设计,相互之间侵入较小,但在既有的架构下,往往须要通过离线 ETL 来转运数据(起因剖析能够参考咱们这篇对存储局部的剖析)。而 F1 Lightning 设计也落在拆散零碎的领域,应用了 CDC 进行实时数据勾兑而非离线 ETL,那毫无疑问,F1 的列存局部设计也须要和咱们一样针对列存变更进行设计。

顺口提一下,论文中剖析相干工作时也提到了 TiDB 和 TiFlash,不过这部分形容却是谬误的,TiDB 和 Lightning 一样能够提供 Strong Snapshot Consistency,甚至因为它的独特设计,还能提供更强的一致性和新鲜度。

Lightning 绝对于既有 HTAP 零碎, 提供了如下几个(TiDB HTAP 也一样领有的甚至更好)劣势

  1. 领有只读的列存正本,提供了更好的执行效率以
  2. 绝对于 ETL 流程,提供了更简略的配置和去重
  3. 无需批改 SQL 间接查问 HTAP
  4. 一致性和新鲜度
  5. 平安方面 TP 与 AP 两局部对立
  6. 设计关注点拆散,TP 和 AP 能够别离针对性优化本人的畛域而不过多牵扯
  7. 扩展性,提供了对接除了 F1 DB 和 Spanner 以外不同的 TP 数据库的可能性

零碎架构

因为我的项目立项的前提是对 TP 零碎无侵入性,因而作为 HTAP 来说,F1 Lightning 的架构设计绝对激进。现有 HTAP 的钻研畛域,大多数我的项目都是以所谓 Greenfield 计划(不受前序计划束缚)为假如,但 F1 Lightning 须要在对现有业务不做任何迁徙且设计方案最大水平不对 TP 零碎做批改(组织架构层面,F1 Lightning 团队也不论 TP 零碎的代码),所以他们做出了一个「A loosely coupled HTAP solution」,这是一个犹如驴标蛇皮袋个别巨浮夸的计划:通过 CDC 做 HTAP。所以实际上,F1 Lightning 是一个 CDC + 可变更列存的计划。

Lightning 分为这么几个模块:

  1. 数据存储:继续承受 CDC 的变更信息并存储到 Lightning 的读优化(列存)正本。
  2. 变更复制:一个分布式的 CDC 通道,从 OLTP 零碎承受事务日志,并将他们散发到不同的存储服务器,并且按需对新接入表进行数据历史回放。
  3. Metadata 数据库:寄存存储节点和变更复制的状态。
  4. Lightning Master:全组件协同和治理。

不过,形成残缺的 HTAP 零碎而言, 还有两个隐含的模块

  1. OLTP 数据源:一直公布 CDC 信息。
  2. 查问引擎:应用 F1 Query,负责从 Lightning 中捞取数据响应查问。

因为 Google 的现有 TP 零碎大多选用 MVCC 模型(实际上 MVCC 在分布式 TP 零碎中也是一个风行的抉择),对于读取语义,Lightning 也抉择了 MVCC 和相应的快照隔离:由 TP 收回的 CDC 如果带着工夫戳向 Lightning 进行复制,MVCC 会是一个最天然而且最不便的设计。而因为分布式 CDC 架构的人造束缚和个性,Lightning 抉择提供 Safe Timestamps 来放弃一致性。这是一个相似水位线的设计,因为通过一次分布式散发,因而不同存储服务器接管到数据将会带来不等同的提早,因而无奈简略保障一致性。所以相似这样水位线的设计能够以数据新鲜度为代价换取查问的快照一致性。相对来说,TiDB HTAP 抉择了更底层的复制计划,借助 Raft 的一致性特型提供了最陈腐且统一的数据,能够说是一种更优雅的计划。

存储

之前的文章剖析过为何列存须要进行非凡的 Delta-Main 设计能力提供实时变更,Lightning 的设计也一样体现了相干的思路。这是一个类 LSM 架构,其中 Delta 信息间接存储于内存中,一旦就位就能够被查问。因为正本和 TiDB 一样位于 OLTP 零碎中能够随时补数据,因而这部分数据也并不会独自记录 WAL。哪怕能够随时补数据,但如果须要回放成吨的数据将会带来微小的复原提早。因而这里也毫无意外地引入了 Checkpoint 机制。因为 Delta 局部由 B+Tree 构造在内存中组织,能够随时无变更写入磁盘作为 Checkpoint。除了 Checkpoint 外,当 Delta 太大占用太多内存的时候,它们也会通过行列转置后写到磁盘上。和 TiFlash 或者 Parquet 等相似,Lightning 的 Delta 磁盘格式选用了很风行的相似 PAX 格局列存:先将一组行组成 Row Bundle,而后再按列切割,其中每个行组附加了一个针对主键的稠密 B+Tree 索引,这个计划能够兼顾点查以及范畴查问。

要反对一致性的读取,Lightning 也和 TiFlash 一样必然会遇到 MVCC 读取版本去重,并且不同存储(磁盘 Delta 和内存 Delta)之间须要进行读取时归并。因为反对了实时 DDL 带来的 Schema 物理多版本,列存解决绝对多了一份表构造苟合(Schema Coercion)的考量:在归并的过程中,数据会被规整为同一 Schema。顺便提一句,因为同样须要思考动静 Schema 变更的反对,TiFlash 的列存引擎也反对了同表不同构造存储。Lightning 采纳了类 LSM 的架构,因而读取也会触发一个 K 路归并,有可能会带来可观的读取性能损失。为了减小归并读取的代价,与 LSM 和 Delta Main 设计相似,Lightning 须要一直整顿数据,解决 Delta 的 Compaction。这部分比拟有意思的点是,因而除了较小的归并操作,其余所有 Compaction 都将交给专门的 Compaction Worker 资源解决。对于这部分的相干原理探讨能够参考咱们的前序博文。

因为 Lightning 须要接入不同的 OLTP 零碎,因而除了多版本 Schema 反对之外,它还有特地的 Logical Schema 和 Physical Schema 的两层映射设计。其中第一层 Logical Schema 对应 OLTP 零碎内的原生 Schema,蕴含了诸如 Protobuf,构造体之类的简单类型,而第二层的物理 Schema 则只蕴含 Lightning 自身的原生类型,比方整数,浮点,字串等。这使得零碎实现能够和数据源的 OLTP 类型零碎大幅解耦。而两者之间靠 Logical Mapping 进行串联,这个映射定义了各个数据类型之间如何从源类型向 F1 类型零碎进行来回翻译(写时由源向 F1 翻译,读时由 F1 翻译回源类型)。

Lightning 应用范畴分片,反对在线 Repartitioning 以期达到负载平衡,而所谓在线就是不会打断数据注入以及查问。Lightning 的分区在大小触或者写入压力涉及阈值的时候会进行决裂,而这种决裂是 Metadata Only 的(只批改 Metadata 中分片的范畴而不是物理切割数据),而决裂产生的分片数据则由老分片的 Delta 继承而来。当查问产生的时候,因为数据 Delta 是原始分片继承,因而须要依据新分片的范畴进行过滤能力读到正确的数据(TiKV 的逻辑 Region 决裂也是相似解决)。在新老交替的档口,新分片会等到同步连贯建设并且数据追上之后才真正变成流动分片,而老的分片也会等波及到的查问实现再进行工作。相似形式,Lightning 也反对分片合并。文章并没有说在决裂和合并之外分片如何在节点之间迁徙。不过因为 Delta 落盘之后存在云存上,因而看起来只有从新为分片重新分配容器,并让分片回放一小段 Checkpoint 之后的新 Memory Delta 就能实现数据迁徙。

总的来说,列存变更要思考的点都是相似的,做的设计也都是相似的。无非是用一个写优化区去缓冲间接写入,而主数据区则是整顿好的大块列存。一直由背景作业将写区向读区归并,以放弃读取速度。不论是咱们还是 Lightning 亦或上古的喜士多零碎都是这么做的。这部分没有太多能够说的。Compaction 看起来有大小和工夫维度的考量,但论文并没有太粗疏形容 Compaction 的策略。Compaction 设计须要联结思考写放大和读取效率:频繁的 Compaction 能够用资源和写放大来换取性能(更激进的数据整顿,让数据更好地维持在一个更优的读取状态,但耗费更多的计算资源以及磁盘写放大)。不过看起来因为是云架构,写云存且能够外挂额定的 Compation Worker,因而哪怕比拟粗犷分层设计和 Compaction 算法应该也能够满足需要。

复制

F1 Lightning 次要依赖的是 CDC 层面的复制,这种复制得以屏蔽很多前端 TP 零碎不同带来的复杂度。组件上来说,变更复制物理上依赖两局部:

  1. Changepump:内置了从不同源 CDC 到 Changepump 能承受的格局间的转换;并且将 Transaction Log 转换成面向 Partition 的变更日志。因为 Lightning 存储也是分片的,因而源零碎事务的回放可能横跨多个分片和服务器,在回放的同时,Changepump 须要维持事务的信息以放弃一致性。
  2. Change subscriber:Changepump 的 Client。Lightning 将一个表分为多个分片,每个分片都保护了一个对 Changepump 的订阅。这个订阅传输保护了一个起始工夫戳(能够指向历史数据),而 Changepump 会依据这个工夫戳来回放变更,由此,这套机制是反对断点续传的。

针对同 Primary Key 的传输是保障前后有序的,但跨 Primary Key 则没有这个保障。这应该使得不同主键数据能够同过不同节点分布式传输而不必通过地方单点来定序。不过随之而来的是,最新的数据逾越主键而言往往无奈维持一致性,因而这套机制还借助了平安水位线来确保可查问的数据是统一的。Changepump 会定期进行产生一个 Checkpoint Timestamp 发送给所有订阅者:所有比这个工夫戳更古老的数据都曾经送达,Lightning 服务器自身就会依据这个信息来修改它自身的平安查问水位线。但这个 Checkpoint 工夫戳的产生在并发环境下并不可能每条变更都修改(Coordinate Cost 会十分高),因而零碎在新鲜度和解决高效性之间做了折中:越快越精准修改水位线必然带来更陈腐的可查问水位线以及解决效率降落,反之亦然。

Changepump 自身是分布式的,在源头上同一个变更日志可能被不同的 Changepump 服务器解决,目的地上同一个订阅也可能连贯不同的 Pump。Changepump 和 Lightning Server 并不是对应的,因为 Changepump 须要平衡的是写入的量,而 Lightning 服务器则是要平衡存储的量。

F1 Lightning 和 TiDB HTAP 最大的不同在于复制设计。TiDB 的复制基于更底层的 Raft Log 设计,这种实现使得 TiDB 能够提供更好的一致性与新鲜度,且简直不须要批改 OLTP 局部的设计。而 F1 的设计则采取了一种更松的耦合,应用 CDC 进行复制。越是底层的复制协定能越大程度放弃复制自身的细节和一致性,而越高层的协定则须要一些勾兑伎俩来放弃一致性,但益处是 OLAP 的存储层能够不必思考太多 OLTP 的设计束缚(例如 TiDB 须要以雷同大小的 Region 为单位进行复制而 F1 Lightning 则不须要)。很惋惜的是对于 Change Replication 局部论文并没有十分具体的形容,这部分对于如何维持一致性以及容错实际上还存在不少能够探讨的细节。例如如何判断一个服务器是没有事务产生,还是回放卡住还是 CDC 没有产生?是否通过心跳发空包来确定存活以推动工夫戳?如何追踪源分区和指标分区之间的映射以推动工夫戳?实际上,对于一个相似 Spanner 这样分布式 OLTP 源库通过 CDC 回放要放弃一致性,并不是那么容易的。而这些论文的论述都稍显太省略,有些遗憾。

容错

因为应用了云存,云存自身保障了数据的高可用,所以 Lightning Server 只须要保障服务高可用即可。因而每个分片会被指派多个 Lightning Server,而这些 Server 别离从 Changepump 拖拽雷同的变更日志(Changepump 内做了内存 Cache 以优化这样反复的拉取),并保护独立的 Memory Delta。然而仅仅有一个主分片会向云存写入数据(包含 disk-resident delta 以及 memory delta checkpoint),当主分片实现写入则会向其余正本服务器发出通知以更新 LSM。这些所有的多个正本都能够同时响应读取服务。当有服务器宕机的时候,新节点会尝试先从分片的其余正本获取数据(这些数据是曾经整顿好的模式,人造的 Checkpoint)而非间接从 Changepump 进行回放。而当轮滚降级的时候,Lightning 也会很小心地不同时重启同分片的多个服务器。

Lightning 配有表级 Failover。当某些时候某张表不可用(压力太大被黑名单,或者数据坏了等),零碎能够主动将查问路由回 OLTP 零碎(因为查问和数据都根本等价)。但用户能够抉择是否进行这样的容错,以防 AP 查问压力打垮 TP。

简略来说容错局部,没有太多新意,不过借助云存容错,能够从 Pump 随时回溯历史,以及无需保障最新数据给了 F1 Lightning 很大的设计空间,不必精密的一致性复制协定也不必太放心会造成读取不统一。

F1 Query 集成

F1 Query 论文能够在这里找到,它能够算作是一个 Federated Query Engine,相似 Apache Spark 和 Presto,能够横跨多个不同的存储引擎以及源数据库。这里应用 F1 Query 作为查问引擎也是题中应有之义。因为联邦查问的特型,用户能够无感知 Query 由行存还是列存来响应。与 TiDB 的解决形式相似,F1 Lightning 能够作为一个非凡的 Access Path 裸露给优化器,以便利用 CBO 的形式来决定是否读取列存。不过有意思的是,F1 Query 并不会在逻辑打算阶段对查问进行辨别:它会产生一个读取行列都一样的逻辑打算,而在物理打算阶段再抉择具体的 Access Path。这里看起来还是有更深的优化空间,例如依据不同索引以及列存独特考量抉择不同 JOIN 程序。另外 F1 Lightning 也同样能够将 Subplan 下推,相似 TiFlash 的协处理器性能,本地化无需 Shuffle 的辅助计算,例如 Filter,Partial Aggregation 以及 Projection。

这部分设计相似 TiFlash + TiSpark / TiDB 的组合。单就 F1 Query 的状态,在 TiDB HTAP 中能够用 TiSpark 代替,两者都同样具备桥接不同存储以及 Subplan 下推的能力。

工程实际

  1. 组件复用:零碎中诸多可能被复用的组件都抽成了独自的库,在多个其余产品中被复用,另外相似 Changepump 这样本来为 Lightning 设计的组件也被相似 TableCache 这样的产品所利用。
  2. 正确性验证:退出了针对行列零碎比照的校验机制。

收益与代价

无疑列存应用会退出额定的正本占用额定的空间,但列存的计算效率更高,而计算资源却是比存储更低廉的。通过剖析,对于 Read Intensive 利用来说,额定的存储能带来大量的计算资源节俭,看起来是值得的。对于混合 Workload 的查问,诸如小型的分布式查问,或者人肉写的 Adhoc 查问,异或 ETL 类作业,Lightning 的列存正本以及计算下推都能够节俭很多计算资源以及工夫。这部分对 TiDB HTAP 也是相似,咱们有用户反馈应用 TiFlash 之后反而用了更少的服务器。

比照 TiDB HTAP

上面是吹捧自家产品环节 :)

总体来说,TiDB HTAP 应用了齐全不同的设计然而达到甚至超过了 F1 Lightning 论文所论述劣势。犹如之前文章所说,咱们最后版的 TiFlash 设计也是基于 CDC 的。然而因为种种原因,这个设计「进化」成了当初基于 Multi-Raft 的样子。两者都立足于解决由行存到列存的异构数据复制的问题,并且两端都可能是分布式系统。相似 SAP Hana 这样由单点 OLTP 到分布式 OLAP 的异构复制无疑会更简略,因为输入的日志是有单机产生,保序和一致性都能以很简略的形式解决。而由多主的分布式系统所产生的日志,要保障一致性则颇费思量。因为源头是多点的分布式系统,那么传输无疑无奈经由单点收纳,那样吞吐必然不够,但多点收纳又很难保障全局的一致性。由此 F1 Lightning 的 CDC 方案设计了简单的工夫戳水位线,用就义新鲜度的形式提供一致性查问机制,但因为自己程度不够,还没有齐全洞悉其背地所有的设计要点,但以 CDC 形式进行异构复制而要确保一致性大抵会是一个绝对简单的设计。相对而言,Raft 的异构复制却有截然不同的个性。经由 Multi-Raft + PD 调度,TiFlash 的复制体系主动达成了负载平衡,无论日志传输,还是是源端写入压力,异或指标端的存储平衡。也因为 Raft 协定提供了 Follower / Learner 正本的一致性读取算法,通过对线性日志的索引校对,TiFlash 能够很容易提供最新数据的读取而无需保护简单的水位线,并且简直齐全等同的 Sharding(Region)设计也使得 Shard 之间的全局一致性能够仅仅靠 Raft 加 MVCC 两重机制就能残缺保障,并且确保读取到「最陈腐」的数据。最陈腐和较陈腐看似只是一小段时间的差别,但实际上和 TiKV 简直雷同的一致性保障使得 TiDB 的行存和列存能够在在线业务甚至同一查问中混合应用而无需思考两者可能提供不同的数据服务,在我看来,这个才算是真正的 HTAP。另外也因为这样的设计,TiFlash 不须要设计另一套天差地别的存储架构,无需额定设计负载平衡无需额定的存储调度,只须要通过现有的 PD,以 TiKV 引擎简直统一的行为运行和运维,大大减小了部署和运维的累赘。总之,集体感觉 TiDB HTAP 的设计是更优雅且优良 :) 当然这里也欢送各位看官在评论区做出本人的评估。

退出移动版