火山引擎湖仓一体剖析服务 LAS(Lakehouse Analytics Service),是面向湖仓一体架构的 Serverless 数据处理剖析服务,供给字节跳动最佳实践的一站式 EB 级海量数据存储核算和交互剖析才能,兼容 Spark、Presto 生态,协助企业轻松构建智能实时湖仓。

LAS 服务是什么?LAS 有哪些优化特性?本文将从根底概念、数据库内核特性优化、数据服务化、事务实践等角度全方位介绍湖仓一体架构在LAS的探究与实践。

LAS服务是什么?

在了解 Las 服务是什么之前,先来了解一下数据渠道全体职业的开展趋势,大概分为三个阶段。

湖仓一体架构在火山引擎 LAS 的探索与实践

第一阶段,一般被称为传统数仓,一种从 1980 年开端的依据传统数据库技能来做的 BI 剖析场景。在这种架构下,一般核算和存储是高度一体的。全体体系能支撑的核算才能,依靠于服务供给商的硬件配置,全体本钱高,存在物理上限,扩展起来比较费事。

第二阶段,跟着技能的演进, 2010 年开端呈现了以 Hadoop 技能体系为主流的传统数据湖。在以 Hadoop 技能为主的数据渠道架构下,一般能够支撑服务在普通硬件上面去部署,全体的核算和存储的扩展性都得到了处理。依据开源技能生态,多个大型公司也参加到数据湖技能开展中来,全体生态昌盛度也在逐步提高。

但在这一阶段凸显出了一个问题,跟着生态技能的开展,越来越多的开源组件开端累积。对于一个企业来说,为了处理不同领域的问题,需求运维多个开源的组件,来满意不同领域的数据需求,就导致整个企业的技能运维本钱逐步提高。

依据这个问题,跟着技能的进一步开展,在 2020 年,湖仓一体的架构开端被提出。

相比起传统数据湖,湖仓一体架构支撑原生的 ACID 才能,支撑像 BI 剖析、报表剖析,机器学习和流式剖析多种类型的核算范式,以及云上的目标存储和弹性核算才能。以上才能,让湖仓一体架构能够有效地去处理企业的对数据规划,以及对核算才能的弹性弹性需求。一起,湖仓一体能够在很大程度上躲避传统 Lambda 架构存在的多个核算组件,或者多种架构范式导致的架构担负,让企业能够更专心地去处理他们的事务价值。

湖仓一体架构在火山引擎 LAS 的探索与实践

LAS 便是依据湖仓一体的架构进行规划的。从上图来看,LAS 架构全体上分为三个部分。最上层是开发工具层,开发工具层会经过核算层供给的一致 SQL 拜访服务去拜访核算层,依据用户的 SQL 类型主动做 SQL 解析。一切引擎核算才能一致由弹性容器服务来供给,能够支撑弹性弹性,按需运用。

再往下便是湖仓一体的存储层。首要,湖仓一体存储会经过一致的元数据服务,向核算层供给一致的元数据视图,屏蔽底层的详细元数据完成细节,能够使多个引擎无缝对接到一致的元数据服务。

接下来是湖仓存储引擎,它首要供给完事务办理才能,也便是 ACID 的才能,以及对数据批流一体的读写才能。

再往下便是 LAS 依据火山引擎目标存储服务 TOS 和 CloudFS ,来供给 EB 级的数据存储才能和数据拜访的缓存加速才能。

以上便是 LAS 全体的技能架构。

LAS数据湖内核剖析

这一版块将向我们呈现 LAS 数据湖内核的特性及优化。

湖仓一体架构在火山引擎 LAS 的探索与实践

LAS 的数据湖内核—— ByteLake它是什么?

首要,ByteLake 是依据开源 Apache Hudi 进行内部增强的湖仓一体存储引擎,供给湖仓一体的存储才能。

它的第一个首要才能是供给了湖仓一致的元数据服务,彻底兼容开源的 Hive Metastore,能够无缝对接多种核算引擎。第二个首要才能是能够支撑对海量数据的 Insert,彻底兼容 Hive SQL,能够平迁传统数仓场景下的 Hive 使命。第三,ByteLake 支撑对大规划历史数据的 Update 和 Delete,以及对新增数据的 Upsert 和 Append 才能。最终,ByteLake 支撑流批一体的读写才能,供给流式读写的 source 和 sink,支撑近实时剖析。

ByteLake又是怎样做到这些才能的呢?接下来从以下几个特性来打开论述。

湖仓一体架构在火山引擎 LAS 的探索与实践

怎样完成高效数据更新?

第一个场景是流式写入更新场景。在这种场景下,最显着的特色便是小批量数据频繁写入更新。但首要的问题是怎样去定位要写入的记载呢?是做 update 操作仍是 insert 操作?

在这样的背景下,ByteLake 供给了一种 Bucket Index 的索引完成计划。

这是依据哈希的一种索引完成计划。它能够快速地去定位一条记载所对应的 Fail Group,然后快速定位当时记载是否现已存在,来判别这一条记载是做 Update 仍是做 Insert 操作,然后能够快速地将这种小规划的数据去添加到 Append Log。在读取时,经过 Compaction 就能够将 LogFile 和 BaseFile 里面的数据进行 Merge 去重,然后到达数据更新的作用。

针对日志数据入湖,一般来说是不需求主键的,这种依据 Hash 索引的完成方法,是需求有 Shuffle 操作的。由于在依据 Hash 的索引完成中,当一批数据过来之后,会依据这一批数据去找别离对应的 File Group,再依据 File Group 去聚合要更新的这些数据,经过同一个 Task,去更新同一个 File Group 来完成原子写入。

在数据 Shuffle 的进程,其实对于数据湖日志写入是有额外的开支的,但 ByteLake 供给了一种 Non index 的完成计划,去掉了索引的约束,能够削减数据 Shuffle 的进程,然后到达快速入湖的才能。

湖仓一体架构在火山引擎 LAS 的探索与实践

存量数据怎样高效更新?

存量数据,一大特色便是数据量大,单表的规划或许有几百 TB ,乃至到 PB 的级别。针对于这种大规划的历史数据的更新场景,怎样去提高更新功能?其实最首要的便是要怎样去下降数据更新的规划。

依据此,ByteLake 提出了一种完成计划——Column Family,将单表多列的场景别离存储到不同列簇。不同的文件能够依据 Row Number 进行聚合,兼并后便是一个完好的行。假如要更新历史数据,只需求去找到要更新的那些列对应的 Column Family 对应的文件,把这些文件做一些局部更新,就能够到达全体更新的作用。然后在很大程度上削减这些非必要数据的扫描,提高存量历史数据更新场景的功能。

湖仓一体架构在火山引擎 LAS 的探索与实践

怎样提高并发功能?

谈到并发,一般会有两部分内容。比方有很多个使命一起去往 ByteLake 引擎里面写数据,这就意味着有大批量的使命去拜访 ByteLake 的 MetaStore Service。在这种场景下,ByteLake MetaStore Service 就会成为一个功能瓶颈。

为了打破这个瓶颈,除了无限的堆加资源之外,另一个比较有效的计划便是添加缓存。经过元数据服务端去缓存比较热点的数据,比方 Commit Metadata 和 Table Metadata,来到达服务端的功能提高。

别的一块,是在引擎侧做优化。比方在 Flink 引擎层面将 Timeline 的读取优化到 JobManager 端。同一个使命下,只要 JobManager 去拜访 Hive ByteLake MetaStore Service,缓存到 JobManager 的本地之后,一切的 TaskManager 只要去拜访 JobManager 本身缓存的 Timeline 信息就能够了。

湖仓一体架构在火山引擎 LAS 的探索与实践

从单个使命的视角来看,比方多个使命要一起去更新同一张表,这种情况下要确保数据的正确性,一起又能确保并发功能,应该怎样来做?ByteLake 供给的处理计划——依据乐观锁的一个并发控制。

针对多使命写同一个表的场景,ByteLake 能够支撑多种并发战略的设置。事务能够依据对数据一致性的要求,以及对数据并发功能的要求,选择灵敏的并发战略,来到达它的数据并发写入的功能指标。

LAS数据湖服务化规划

这个版块将向我们呈现 ByteLake 服务化进程中的一些规划实践。

湖仓一体架构在火山引擎 LAS 的探索与实践

CatalogService :一致的 元数据 视图

CatalogService 首要供给了与 HMS 的兼容接口,一起为一切的查询引擎供给了一致的元数据视图,处理了异构数据源的元数据办理问题。

CatalogService 全体分三层,第一层是 Catalog Federation,供给一致的视图和跨地域的数据拜访才能。以及供给了对源数据恳求的路由才能,能够依据元数据恳求的类型,支撑经过 Mapping 的方法,来路由不同的服务恳求对应的底层元数据服务实例。

第二层是 CatalogService 基层的详细元数据服务的完成,比方 Hive MetaStore Service 以及 ByteLake MetaStore Service 等。或许还有不同的元数据服务对接到 CatalogService,来一致向上层引擎供给这种元数据服务。

最终一层是 MetaStore 的存储层,它经过插件式的方法来供给不同的存储引擎,来满意上层不同元数据服务实例的存储要求。

BMS 详解

湖仓一体架构在火山引擎 LAS 的探索与实践

湖仓一体元数据办理服务

Bytelake MetaStore Service,简称 BMS,它是一个湖仓一体的元数据办理服务,全体的架构分为以下几个部分。首要第一个便是 Catalog,Catalog 是对单表的元数据拜访的抽象。首要逻辑是经过 MetaStore Client 来拜访 Meta Server,一起它会去缓存单表的 Schema 信息以及特点等信息。

别的一部分便是 Meta Server,也便是 BMS 里面最中心的部分。它首要是包括两大部分服务层,第一是 Bytelake MetaStore 元数据服务模型,比方 Table Service,Timeline Service,Partition Service 和 Snapshot Service。存储层供给了 MetaStore 一切元数据的存储才能。最终一部分便是 Eventbus, Eventbus 首要意图是为了将元数据的 CUD 工作发送给监听者,来到达元数据信息的分发和同步。

湖仓一体架构在火山引擎 LAS 的探索与实践

元数据写入流程

关于元数据写入流程,简略来讲,当有一个 Client 去提交了 Instant 之后,Bytelake Catalog 会去拜访 Bytelake Meta Store 的接口,会将 Instance 改成 Completed,然后将恳求发到 Bytelake 的 MetaStore,之后 Bytelake MetaStore Server 会做一个原子提交。

在此之后,Timeline Service 会把提交的状况更新到数据库里面。接下来这些分区信息将再被提交给 Partition Service,同步到对应的分区存储表里去。最终一步,把这些一切的改变作为一个快照,同步到 Snapshot Service 里,它会把文件层面的改变存储到数据库里,做耐久化存储。

湖仓一体架构在火山引擎 LAS 的探索与实践

元数据读取流程

对于源数据的读取流程,举个例子,有一个核算引擎它读取了一个 SQL,经过SQL 解析拿到一张表,这张表会经过Bytelake Catalog Service去恳求BytelakeMetaStore,最终会路由到 Table Service 拿到这些表的信息。

拿到表的信息做 SQL Plan 优化的时候,会做一些分区的下推或裁剪。这个时候会去恳求到 Bytelake 的 Partition Service 做过滤,接着会依据分区信息去扫描文件,在此进程中会去恳求 Timeline Service 获取对应的 Timeline 信息。接下来,依据 Timeline 的信息时刻去 Snapshot Service 拿到对应文件,再经过 SQL 履行器来完成数据文件的读取。

湖仓一体架构在火山引擎 LAS 的探索与实践

元数据改变通知

元数据改变通知详细的完成流程首要依托于两个部分。

一是 Eventbus,二是 listener。一切的元数据恳求都会发送到 Eventbus,由 Eventbus 分发工作到一切现已注册的 Listener 上面。listener 再依据下流体系的需求,去订阅 Eventbus 里面的对应工作类型进行响应,然后到达让上下流的组件感知到元数据的变化,完成元数据的同步。

TMS详解:

湖仓一体架构在火山引擎 LAS 的探索与实践

一致表办理服务

LAS 的别的一个服务——TMS,全称是 Table Management Service。它首要处理的问题是异步使命的保管优化。为什么会做异步使命的保管优化?由于正常来讲,Flinker SQL 使命写 ByteLake 表的进程,其实便是把批量的数据写入下流表里面去。跟着时刻的推移,一个是 Commit 的日志十分多,别的一个是小文件十分多。一般的 Flink 引擎层面的完成计划,是在数据写了一定的次数后,追加一个 Compaction 操作,把之前写入的文件做一个紧缩。

但针对流式使命去做 Compaction,对正常的流式使命稳定性有很大影响,由于紧缩本身是一个开支比较大的动作,对流式核算资源的耗费是很难去评估的,会导致整个流式写入使命的动摇,然后影响流式写入使命的稳定性。

依据此,LAS 供给了一个一致的表办理服务,异步保管这些本身内置到引擎内部的使命,一致由 Table Management Service 来保管。它全体的架构是一个主从架构,首要包括的组件一个是 Event Receiver,用来接收 Metastore 下发的一个 Event。PlanGenerator 便是依据 Meta store Server 下发的 Event 信息,来触发 Action Plan 的生成。

什么是 Action Plan?简略讲,便是这一次要做哪些工作,比方你要做一个紧缩使命,仍是做一次历史文件的整理,仍是做一些小文件的兼并,都称为 Action Plan。Job Scheduler 便是去调度需求被履行的 Acting Plan。

什么是 Job Manager?它首要用于和集群交互,比方 Yarn 或 K8S,办理 Action Plan 对应的履行使命,做一些使命运维层面的工作。

湖仓一体架构在火山引擎 LAS 的探索与实践

履行计划生成

就履行计划生成打开来讲,Plan Generator 会接收 Metastore 下发的一些工作,依据用户在表的 DDL 里的配置战略,来决议是否要生成履行计划。

这个战略一般会有几种,比方,一种依据它 Delta Commit 的数量,接连提交了屡次到达了一定的阈值,就会触发一个 Action Plan 的生成,来做一次数据的紧缩。别的一种,是依据 Log File 的大小,来判别 Compaction 操作是否需求履行。PlanGenerator 战略会依据当时 Log File 的 Meta 信息,来决议是否要触发 Action Plan 的生成。

湖仓一体架构在火山引擎 LAS 的探索与实践

履行计划调度办理

履行计划生成结束之后,最终一步便是怎样去调度办理履行计划。履行计划调度的中心流程首要由 Job Scheduler 来做,Job Scheduler 会守时地去轮询现已生成的 Action Plan,再分发给 Job Manager。Job Manager 拿到了 Action Plan 之后,会到集群上提交一个使命,一起不断去轮询使命的状况,更新使命的状况到数据库,确保 Action Plan 履行的可靠性和稳定性。一般 JobScheduler 一般会有先进先出的调度战略,来确保 Action Plan 到达预期调度作用。

LAS在字节跳动的事务实践️

湖仓一体架构在火山引擎 LAS 的探索与实践

抖音电商在湖仓一体架构下的事务实践

抖音电商的事务场景,首要是营销大促、流量诊断以及物流状况的监控。他们的事务痛点是什么?数据量大,核算逻辑杂乱,同质数据源也比较多,宽表的构建本钱比较高,包括一些其他的技能问题。还有一个痛点便是核算周期长,增量核算本钱比较高。

依据 LAS 湖仓一体架构下,能够处理哪些问题呢?

首要,经过 LAS 快数据入湖才能,能够处理多数据源的快速入湖。把外部的事务体系和事务日志,经过 LAS 这种实时入湖才能快速导入到 ODS 层。经过离线数仓能够直接引用 ODS 层的准实时入库数据,来到达离线数仓的日增量数据,同步提高数据的时效性。

其次,实时数仓中 DW 层的一些明细数据,也能够经过流式入湖的才能,直接导入到 ByteLake,到达数据复用的意图。当把这些数据导到了 ByteLake 之后,针对大宽表场景,就能够依据 ByteLake 的多流拼接才能,直接在底层的存储引擎层,完成宽表的构建。然后处理在常规场景下,经过 Flink SQL 做多源或多流 join,导致的使命状况比较大,或者使命处理杂乱度比较高的这种稳定性问题,然后更好地去确保事务数据的及时性和稳定性。

湖仓一体架构在火山引擎 LAS 的探索与实践

消费职业传统 数仓 架构晋级

消费职业的客户场景,实际便是在零售场景下的财务办理、库存办理相关的一些核算场景。客户的完成计划依据传统的数据库,事务和离线剖析的恳求都是一致在一个传统数据库上边来做的。

在这种场景下,其实整个 RDBMS 要一起承接事务处理逻辑和离线 ETL 剖析逻辑。跟着事务数据量的增加,很快就会发现传统数据库的核算才能和存储支撑才能到达了上限,导致核算才能缺乏,扩展性比较差,无法在满意后续的事务数据规划的上量。

LAS 针对这种场景的处理计划,是将客户的离线 ETL 的剖析场景,经过实时集成的方法直接导入到 LAS 里面,经过 LAS 的弹性核算才能,为用户的 ETL 剖析场景供给有效的算力确保。在满意客户低本钱约束的情况下,到达客户预期的核算作用,和对数据产出的及时性的要求。一起会经过云上的 ByteHouse 服务来处理客户自建的 CK 的运维本钱以及功能调优的问题。优化了原有的依据 RDBMS 的数据链路,确保事务数据量快速增加的一起,满意它的底层的算力要求。

湖仓一体架构在火山引擎 LAS 的探索与实践

湖仓一体架构下的批流交融核算

典型场景便是数据实时入湖,客户的数据源会经过 Flink SQL 继续地去写入到 LAS 的 Bytelake 表里。但下流假如是一个离线使命,其实用户没办法很便当地去判别数据写到了哪个方位,或者分区数据现在是不是现已齐备的。

假如仅依靠体系时刻来完成,比方在上游的这种 Flink SQL 使命,在写入进程正常时倒没有特别大的问题。但是一旦上游 Flink SQL 使命呈现一些数据积压或者使命反常的场景,下流依靠体系时刻去调度,就会存在某些分区会呈现数据空泛或数据偏移的问题。例如原本数据应该落在 7 点的分区,由于上游的这些 SQL 使命的消费延迟,导致 7 点的数据并没有准时地落下来, 导致下流去消费 7 点的数据的时候,拿到的是一个不完好的数据,导致呈现数据空泛或数据偏移的问题。

针对这种场景,LAS 供给了一种叫归档的才能,也便是在 Flink SQL 写入的进程中,会依据事务工作时刻实时写入对应的数据分区。经过 ByteLake 供给归档才能,分区数据就绪后,可主动生成一个归档标签。下流的 spark SQL 使命能够依据分区是否有归档标签,来判别对应分区的数据是否就绪,来决议当时离线使命是不是要调度起来。

这项才能的完成逻辑,其实便是 Flink SQL 每次去提交一个 Commit 的时候,会去判别当时提交的事务的工作时刻,是否比当时的未提交分区的时刻超过了某一个阈值。比方当时分区的时刻是 7 点,Flink SQL 在继续提交微批数据的时候,它判别出来当时的最小的事务时刻现已到 7 点半了,而事务定义的可容忍的延迟间隔是 15 分钟, ByteLake 以为这个数据其完成已写完了,就会把 7 点的分区数据打上一个归档标签,来标示数据现已完成了。下流就能够去正常地去消费 7 点的分区数据,然后确保数据的完好性。

在供给了这种归档才能的情况下,LAS 的全体核算链路就能够完成批流交融。比方 ODS 的 ByteLake 表是一个准实时的表,基层的 Spark SQL 使命能够直接经过 Spark ETL 去做处理,产出一个离线表。或许后边还会有一些 SQL 场景依靠离线表做数据的准实时消费。在这种情况下,Flink SQL 会再生成一张 ByteLake 表,这张表同样能够被下流的 Spark SQL 的离线使命依靠,然后到达在整个 Pipeline 里,做到批流核算相互交融的状况。