本文收拾自火山引擎云原生核算研发工程师刘纬在 DataFunCon 2022 上的讲演。跟着事务的发展,字节跳动特征存储已到达 EB 等级,日均增量 PB 等级,每天练习资源量级为百万 Core。随之而来的是内部事务方对原始数据存储、特征回填需求、下降本钱、提升速度等需求的期待。本次共享将环绕问题布景、选型& Iceberg 简介、依据 Iceberg 的实践及未来规划展开。

作者:刘纬

收拾:王吉东,于惠

问题布景

用户运用流程

如咱们所知,字节跳动是一家拿手做 A/B test 的公司。以特征工程调研场景为例,流程如下:

  • 首先由算法工程师进行在线特征抽取;
  • 将抽取到的特征,运用 Protobuf 的格局按行存至 HDFS;出于存储本钱的考量,一般只存储抽取后的特征,而不存储原始特征
  • 将 HDFS 存储的特征交由字节自研的分布式框架( Primus )进行并发读取,并进行编码和解码操作,然后发送给练习器。
  • 由练习器对模型进行高效练习假如模型练习效果符合算法工程师的预期,说明该调研特征生效,然后算法工程师对调研特征进行回溯,经过 Spark 作业将特征回填到前史数据中,共享给其他算法工程师,然后迭代更多的优质模型假如模型练习效果不符合算法工程师的预期,则调研特征不对原有特征调集产生影响

字节跳动湖平台在批计算和特征场景的实践

事务规划

公司巨大的事务规划,带来了巨大的核算和存储体量:

  • 特征存储总量达 EB 级;
  • 单表特征最大可达百 PB 级(如广告事务);
  • 单日特征存储增量达 PB 级;
  • 单日练习资源开支达 PB 级。

字节跳动湖平台在批计算和特征场景的实践

遇到的问题

当特征调研场景叠加巨大的数据体量,将会遇到以下困难:

  • 特征存储空间占用较大

  • 样本读扩大,不能列裁剪,很难落特征进样本;

  • 样本写扩大,COW 很难做特征回溯调研;

  • 不支撑特征 Schema 校验;

  • 平大驾到端体会差,用户运用本钱高

选型& Iceberg简介

在特征调研场景下,行存储是个低效的存储方法;因而,咱们挑选 Iceberg 存储方法来处理上述问题。

全体分层

字节跳动湖平台在批计算和特征场景的实践

Apache Iceberg 是由 Netflix 公司推出的一种用于大型剖析表的高功用通用表格局完成方案。

如上图所示,体系分红引擎层、表格局层、文件格局层、缓存加快层、对象存储层。图中能够看出,Iceberg 所处的层级和 Hudi,DeltaLake 等东西相同,都是表格局层:

  • 向上供给一致的操作 API
  • Iceberg 界说表元数据信息以及 API 接口,包括表字段信息、表文件组织形式、表索引信息、表核算信息以及上层查询引擎读取、表写入文件接口等,使得 Spark, Flink 等核算引擎能够一起高效运用相同的表。
  • 基层有 parquet、orc、avro 等文件格局可供挑选
  • 下接缓存加快层,包括开源的 Alluxio、火山引擎自研的 CFS 等;CFS 全称是Cloud File System, 是面向火山引擎和专有云场景下的大数据一致存储服务,支撑高功用的缓存和带宽加快,供给兼容 HDFS API 的拜访接口。
  • 最底层的实际物理存储,能够挑选对象存储,比如 AWS S3,火山引擎的 TOS,或许能够直接运用 HDFS。

经过上图能够比较明晰地了解到,Iceberg 这个笼统层最大的优势在于:将底层文件的细节对用户屏蔽,将上层的核算与基层的存储进行分离,然后在存储和核算的挑选上更为灵活,用户能够经过表的方法去拜访,无需关心底层文件的信息。

Iceberg简介

Iceberg 架构

字节跳动湖平台在批计算和特征场景的实践

Iceberg 的实质是一种文件的组织形式。如上图所示,包括多级的结构:

  • Iceberg Catalog:用于保存表和存储途径的映射关系,其中心信息是保存 Version 文件地点的目录。Iceberg Catalog 共有8种完成方法,包括 HadoopCatalog,HiveCatalog,JDBCCatalog,RestCatalog 等不同的完成方法,其底层存储信息会略有不同;RestCatalog 方法无需对接任何一种具体的存储,而是经过供给 Restful API 接口,凭借 Web 服务完成 Catalog,进一步完成了底层存储的解耦。

  • Metadata File:用来存储表的元数据信息,包括表的 Schema、分区信息、快照信息( Snapshot )等。Snapshot 是快照信息,表示表在某一时间的状态;用户每次对 Table 进行一次写操作,均会生成一个新的 SnapShot。 Manifestlist 是清单文件列表,用于存储单个快照的清单文件。Manifestfile 是存储的每个数据文件对应的清单文件,用来追寻这个数据文件的方位、分区信息、列的最大最小值、是否存在 Null 值等核算信息。

  • Data File 是存储的数据,数据将以 Parquet、Orc、Avro 等文件格局进行存储。

Iceberg 特色

  • SchemaEvolution:Iceberg 表结构的更新,实质是内涵元信息的更新,因而无需进行数据搬迁或数据重写。Iceberg 确保形式的演化( Schema Evolution )是个独立的、没有副作用的操作流程,不会触及到重写数据文件等操作。

  • Time travel:用户可任意读取前史时间的相关数据,并运用完全相同的快照进行重复查询。

  • MVCC:Iceberg 经过 MVCC 来支撑事务,处理读写抵触的问题;

  • 敞开标准:Iceberg 不绑定任何核算引擎,拥有完全独立敞开的标准,易于拓宽。

Iceberg 读写流程和提交流程

字节跳动湖平台在批计算和特征场景的实践

1.读写

  • 每次 Iceberg 的写操作,只有在产生 Commit 之后,才是可读的;如有多个线程一起在读,一部分线程在写,就只有在 Commit 悉数数据之后,对用户进行的读操作才能被用户的读线程所看到,然后完成读写分离。
  • 例如上图中,在对 S3 进行写操作的时分,S2、S1 的读操作是不受影响的;此刻 S3 无法被读到,只有Commit 之后 S3 才会被读到。此刻 Current Snapshot 会指向 S3。
  • Iceberg 默许从最新 Current Snapshot 读取数据;假如读更早的数据,可经过指定对应的 Snapshot ID ,完成数据回溯。

2.事务性提交

  • 写操作:记载当时元数据的版本——Base Version,创建新的元数据以及 Manifest 文件,原子性将 Base Version 替换为新的版本。

  • 原子性替换:原子性替换确保了线性前史,经过元数据办理器所供给的才能,以及 HDFS 或本地文件体系所供给的原子化 Rename 才能完成。

  • 抵触处理:依据达观锁完成,每一个 Writer 假定当时没有其他的写操作,即对表的 Write 进行原子性的 Commit,若遇到抵触则依据当时最新的元数据进行重试。

分区裁剪

  • 直接定位到 Parquet 文件,无需调用文件体系的 List 操作;

  • Partition 的存储方法对用户通明,用户在修正 Partition 界说时,Iceberg 能够自动地修正存储布局,无需用户重复操作。

谓词下推

Iceberg 会在两个层面完成谓词下推:

  • 在 Snapshot 层面,过滤掉不满意条件的 Data File;
  • 在 Data File 层面,过滤掉不满意条件的数据。

其中,Snapshot 层面的过滤操作为 Iceberg 所特有,正是利用到 Manifest 文件中的元数据信息,逐字段完成文件的筛选,大大地削减了文件的扫描量。而同为Table Format 产品、在字节其他事务产线已投入运用的 Hudi,虽然相同具有分区剪枝功用,但是尚不具有谓词下推功用。

依据 Iceberg 的实践

Hudi、Iceberg、DeltaLake 这三款 TableFormat 产品各有优劣,但是并没有任何一款产品能够直接满意咱们的运用场景需求;考虑到 Iceberg 具有杰出的 Schema Evolution 才能、支撑下推,且无需绑定核算引擎等长处,因而字节挑选运用 Iceberg 作为数据湖东西。

全体架构

字节跳动湖平台在批计算和特征场景的实践

  • 在字节的全体架构中,最上层是事务层,包括抖音,头条,小说等字节绝大部分事务线,以及火山引擎云原生核算等相关 ToB 产品(如 Seveless Spark 等);
  • 在渠道层,运用 Global Lake Service 给事务方供给简略易用的 UI 和拜访操控等功用;
  • 在框架层,运用 Spark 作为特征处理框架(包括预处理和特征调研等),运用字节自研的 Primus 分布式框架作为练习框架,运用 Flink 完成流式练习;
  • 在格局层,挑选 Parquet 作为文件格局,运用 Iceberg 作为表格局;
  • 最基层是调度器层和存储层。挑选 Yarn 和 K8S 作为调度器;存储层一般挑选 HDFS 进行存储,关于 ToB 产品,则运用 CFS 进行存储。

Data-Parquet

字节跳动湖平台在批计算和特征场景的实践

结合上图能够看出,列存储在特征调研场景存在以下优势:

  • 可挑选指定列进行读取:有效削减读扩大问题,一起易于增列,即新增一列的时分,只需单独写入一列即可,元数据信息会记载每一列地点的磁盘方位;
  • 紧缩:同一列的数据格局相同,因而具有更好的紧缩比;同一列的数据名称相同,因而无需进行冗余字符串存储;
  • 谓词下推:对每一列数据记载相应的核算信息(如 Min,Max 等),因而能够完成部分的谓词下推。

为了处理事务方的痛点问题,咱们改成运用 Parquet 列存储格局,以下降数据的存储本钱;一起因为 Parquet 选列具有下推到存储层的特性,在练习时只需读取模型所需求的特征即可,然后下降练习时序列化、反序列化的本钱,提升练习的速度。

但是运用 Parquet 列存储,带来长处的一起也相应地带来了一些问题:

  • 原来的行存储方法是依据 Protobuf 界说的半结构化数据,无需预先界说 Schema;但是运用 Parquet 之后,需求预先指定 Schema 才能进行数据的存取;这样在特征新增和淘汰的时分,Schema 的更新将会变成一个扎手的问题。
  • 此外,Parquet 不支撑数据回填;假如需求要回填比较长的数据,就需求将数据全量读取,添加新列,再全量写回。这样一方面会造成很多核算资源的糟蹋,另一方面会带来 Overwrite 操作,导致正在进行练习的使命因为文件被替换而失利。

为了处理以上两个问题,咱们引入了Iceberg 来支撑 SchemaEvolution,特征回填以及并发读写。

特征回填

COW

字节跳动湖平台在批计算和特征场景的实践

从上图能够看出,运用 Iceberg COW( Copy on Write )方法进行特征回填,经过 BackFill 使命将原快照中的数据悉数读出,然后添加新列写出到新的 Data File 中,并生成新的快照。这种方法的缺陷在于,仅仅新增一列数据的写入,却需求全体数据悉数读出后再悉数写回,糟蹋了很多的核算资源和存储资源;因而,咱们依据开源的 Iceberg 自研了一种 MOR( Merge on Read )的 BackFill 方案。

MOR

字节跳动湖平台在批计算和特征场景的实践

从上图能够看出,在 MOR 方案中,咱们依然需求一个 BackFill 使命来读取原始的 Data File 文件;所不同的是,咱们只需读取少量需求的字段。例如对 A 列经过一些核算逻辑生成 C 列,那么 BackFill 使命只需从 Snapshot1 中读取 A 列的数据,且只需将 C 列的 Update 文件写入 Snapshot2 即可。

跟着新增列的增多,需求将 Update 文件兼并到 Data File 里边;为此,能够进一步供给一种 Compaction 逻辑,即经过读取旧的 Data File 和 Update File,兼并生成新的 Data File。完成细节如下:

  • 旧 Data File 和 Update File 添加一个主键,每个文件按照主键排序;
  • 读取旧 Data File 时依据用户挑选的列,剖析具体需求哪些 Update File 和 Data File;
  • 依据旧 Data File 中 Min-Max 值去挑选对应的 Update File。

由此能够看出,MOR 的实质是对多个 Data File 文件和 Update File 文件进行多路归并,归并的顺序由 SEQ 决定,SEQ 大的数据(标明数据越新)会掩盖 SEQ 小的数据。

两种特征回填方法对比

  • COW:读写扩大严重、存储空间糟蹋、读取逻辑简略、写入消耗更多资源、读取无需额外核算资源;
  • MOR:没有读写扩大、节约存储空间、读取逻辑复杂、写入消耗较少资源、绝大多数场景,不需求额外资源;

相比于 COW 方法的全量读取和写入,MOR 的优势在于只读取需求的列,相同也只写入更新的列,因而避免了读写扩大的问题,节约很多核算资源,并大大下降读写 I/O;相比 COW 方法每次 COW 翻倍的情况,MOR 只需存储新增列,很多节约了存储资源。

关于模型练习使命而言,大多数模型练习只需求用到少量的列,因而很多的线上模型都无需 MOR 操作,触及开支可忽略不计;关于少量的特征调研模型,只需读取模型对应的 Update File 即可,因而带来的读取资源添加也非常有限。

其他

字节跳动湖平台在批计算和特征场景的实践

除了上面说到的凭借 Compaction 提高读功用以及剖析特征删去场景外,还供给了以下几个服务:

  • ExpirationSnapshot Expiration: 用于处理过期的 Snapshots。过期 Snapshots 不及时整理,会导致元数据文件堆积,然后带来文件胀大问题,会给算法工程师带来困扰,因而需求服务定时做一些整理。咱们经过渠道化改造完成 Snapshots 文件的一致保护和整理;Data Expiration: 大部分数据是有新鲜度和时效性的,因而用户可设置数据保存多久后被整理。

  • CleanUp:因为一些事务的失利,或许一些快照的过期,导致文件在元数据文件中已经不再被引用,需求定时整理掉。

  • Roll-Back:关于一些在 Table 中非预期数据或许 Schema 改变,期望将其回滚到之前稳定的 Snapshot;结合渠道的事件办理器,能够比较简单的完成这一功用。

  • Statistics: 用来完成一些湖渠道可视化信息的展示,以及后端服务给事务带来的价值归纳。

渠道化改造

字节跳动湖平台在批计算和特征场景的实践

这儿共享下自字节内部完成的渠道化作业。上图是批式特征存储的列表,凭借站内完成的湖渠道化作业,事务部门能够轻松完成特征的可视化操作,以及信息概览的获取。

下图是一张特征表样例,经过这张表能够直观地看到存储空间的运用、文件数的核算、记载数核算、特征核算等信息。

字节跳动湖平台在批计算和特征场景的实践

未来规划

规划重点

在未来规划中,方案逐步支撑以下功用:

  • 湖冷热分层:在本钱优化方面,能够经过湖冷热分层完成。前文说到关于保存超过一定时间的数据,能够直接删去;但是在某些特定的场景下,这些数据还会被运用,仅仅拜访频率较低;因而未来考虑添加数据湖冷热分层功用,协助用户下降本钱。

  • 物化视图:在查询优化方面,经过物化视图提升查询功用。该功用是源于 ToB 客户的真实场景需求,目前这部分的优化作业正处于商业化交付流程中,我们能够后续在火山引擎官网相关的产品上进行体会。

  • Self-Optimize:在体会优化方面,完成 Self-Optimize,例如前文说到的一些数据保护的优化等。

  • 支撑更多引擎:为了添加生态的丰厚度, Iceberg 在未来也会逐步更多的引擎。

全体渠道架构总览

字节跳动湖平台在批计算和特征场景的实践

全体渠道架构以核算引擎产品为中心,包括两部分服务:

  • 云原生办理操控:Quota 服务、租户办理服务、运行时办理、生态整合服务、交付布置服务、网关服务;
  • 云原生运维渠道:组件服务生命周期办理、Helm Chart 办理、日志&审计、监控报警、容灾&高可用;

如前文所述,该渠道不仅支撑公司内部的事务,还会支撑一定的 ToB 的事务,以上在字节内部完成的功用,以及未来规划的才能也会依据内外一致的思路进行演进;终究都会落地到上图中触及到的几款云原生核算产品中,如流式核算 Flink 版,云原生消息引擎 BMQ,云查找服务 OpenSearch,大数据文件存储 CloudFS 等。以上均为 Serverless 的全保管产品,让用户更聚焦于自己的事务逻辑,削减数据运维带来的困扰。

如有需求,欢迎填写问卷,参加技术交流「链接」