Amoro Mixed Format 适用场景及原理解析

01 背景

大家好,我是 Amoro 社区的竹堂。我们团队从2019年开始调研包括 Apache Iceberg、Apache Hudi 等一类数据湖新型表格式。当时的初衷是为实时计算寻找一种新型的存储方案,基于它为业务打造一套具有流批一体和湖仓一体特性的大数据存储方案。

团队最终选择了 Apache Iceberg,并且基于它在内部进行了大量的实践。在实践过程中,我们逐渐发现有一些场景直接使用 Apache Iceberg 将较难满足用户的需求,所以我们在 Apache Iceberg 的基础上设计并实现了 Mixed-Iceberg 和 Mixed-Hive 两种新的表格式,它们继承了 Apache Iceberg 的所有功能特性,并在实时场景下进行了一些优化和功能补充,使得能够更好地满足部分场景的需求。设计实现过程中我们坚持不修改 Apache Iceberg 表格式的结构,只在上层进行封装扩展,以使得 Mixed Format 具备较好的兼容性。

为了更加方便地使用 Apache Iceberg 与 Mixed Format 格式的表,团队研发了湖仓管理平台 Amoro,并在2022年将它开源。作为湖仓管理平台,Amoro 汇总了数据湖中所有表的元信息,基于此再以插件的方式扩展各种管理功能,包括自动的文件合并、数据清理等。管理功能方面 Amoro 对 Apache Iceberg 和 Mixed Format 做了同样的支持,而 Mixed Format 作为 Apache Iceberg 在一些功能上的补充满足更多实时场景的需求。

02 Mixed Format 的适用场景

如 Amoro 用户手册(https://amoro.netease.com/docs/latest/#user-cases)中所说,当前使用 Amoro 构建湖仓一体架构的的主要用户场景包括:

  • 实时湖仓:将包括数据库 CDC、业务日志、传感器数据等源端数据实时写入数据湖中,在之上进行数据分析或进一步数据加工。

  • 流批一体:统一实时与离线数据存储,使用实时计算完成数据分层加工,降低数据延迟,离线按需进行数据修正。

  • 云原生湖仓:基于对象存储、容器化等云原生技术搭建数据仓库,提供弹性扩展、价格低廉的湖仓服务。

Apache Iceberg 和 Mixed Format 都可以应用到三个场景下,Mixed Format 在实时湖仓和流批一体场景下做了更多优化。

实时湖仓

在实时湖仓场景下, Apache Iceberg 解决了以往 Apache Hive 不支持实时更新的问题,简化了数据摄入链路,降低了数据延迟。在这个场景下,Mixed Format 在 Apache Iceberg 之上还做了下面的优化:

更强的主键约束

当前 Apache Iceberg 只在 Flink 引擎内支持了主键定义,Mixed Format 在 Spark 引擎内也扩展了主键定义,并且无论是通过 Flink 还是 Spark 写入数据,都能保证数据在主键上的唯一性。

Merge-On-Read 性能优化

在实时更新场景下,会使用到 Apache Iceberg 的 Row-Level-Delete 特性,而在数据读取时则会使用 Merge-On-Read 技术临时合并写入的增量数据。在 Amoro 的 Self-optimizing 功能的加持下,Apache Iceberg 在此场景下已经能达到一个让人满意的查询性能,但是如果自动优化停滞了,表上的查询性能则可能急剧下降。Mixed Format 在表上引入了文件自动分桶的特性,优化了 Merge-On-Read 的性能,能够在优化不及时的情况下,仍能一定程度保证表的读取性能。

历史 Hive 表兼容

Apache Iceberg 提供了工具将历史的 Hive 表转换成 Iceberg 格式的表,转换过程无需对数据进行重写,转换后需要使用各个引擎的 Iceberg Connector 来访问表。不过如果一些已经在使用的平台或组件尚未完成对 Iceberg 的适配,则很难直接对历史表进行升级,进一步也无法使用到 Iceberg 带来的诸多特性。Mixed-Hive 表格式具备兼容 Hive  表原有元数据的能力,使得即使在表升级到 Mixed-Hive 表之后,仍然能使用 Hive Connector 来访问这张表,做到对平台与组件的100%兼容。

流批写入冲突解决

实时湖仓场景下,实时任务会持续对表进行写入,如果此时有批量更新部分数据的需求,则可能造成流与批的写入冲突。Apache Iceberg 有一套冲突检测机制,在流与批写入的数据不冲突时,两则都能正常写入,如果写入的数据存在冲突则会使后写入的任务因为冲突而无法正常提交。而在一般情况下由于批量更新执行时间更长,所以批量更新基本无法提交成功,此时需要停止实时写入,等批量更新完成后再重新打开实时写入任务。写入冲突无法规避,但是却可以按照一定规则自动解决数据冲突,Mixed Format 设计了一套冲突自动解决机制,使得流与批都可以更新成功,且最终数据满足用户预期。

流批一体

在流批一体场景下,Apache Iceberg 不仅支持流和批的数据写入,同时也支持流和批的数据读取,基于 Apache Iceberg 可以搭建流批统一的开发链路。Mixed Format 在此基础上做了下面的优化:

CDC 数据实时读取

Apache Iceberg 的实时读取功能暂时只支持 append-only 表,对于数据库 CDC 等含有更新的数据,写入 Iceberg 表之后无法实时地读取出来。Mixed Format 增强了表上的实时读取能力,使得能够实时读取 CDC 数据。

秒级实时数据延迟

Apache Iceberg 基于文件读取实时数据,数据的延迟取决于写入时的提交间隔,一般为分钟级。在一些对实时读取延迟要求较高的场景,分钟级的数据延迟无法满足要求。Mixed Format 支持组合 Kafka 等消息队列提供秒级延迟的实时数据。

实时维表关联

在实时数据开发中,维表关联是一个极其常见的场景,很可惜 Apache Iceberg 暂时还没有支持 Flink 下的维表关联,Mixed Format 补齐了这一块的功能。

03 Mixed Format 的原理解析

Mixed Format 的结构

图片

Mixed Format 由3部分组成:

LogStore: 可选的实时数据的秒级缓冲层。一般为 Kafka 这类消息队列上的一个 topic,在实时 pipeline 构建中用来提秒级延迟数据的读取能力。

ChangeStore: 实时数据的存储层。为一张单独的 Iceberg 表,实时的 CDC 数据会以 append 的形式写入以提供最高效的写入能力。可以用来进行数据分析,同时也能为下游实时 pipleline 任务提供分钟级延迟的流式数据。

BaseStore: 存量数据的存储层。为一张单独的 Iceberg 表,ChangeStore 中的数据定期会通过 optimizing 任务去重后重写入 BaseStore。通常用来进行表上的数据分析。

Flink 实时写入任务会同时写入 LogStore 和 ChangeStore,同时 LogStore 和 ChangeStore 又可以作为下游任务的源,分别提供秒级及分钟级的实时数据。

Spark Overwrite 批量更新任务可以直接写入BaseStore,而 Insert into/Update/Delete/Merge into 等 SQL 则写入ChangeStore 以保证主键上的唯一性。

数据自动分桶

为了提升 ChangeStore 与 BaseStore 的合并效率,同时提升两者之上的 Merge-On-Read 性能,Mixed Format 引入了一套自动分桶策略。ChangeStore 与 BaseStore 的合并过程本质上是两者在主键上的一次 Join 关联,关联后相同主键的数据取最新的一条,如果最新的数据的操作类型为删除,则将数据从表中删除。自动分桶是指在写入时则按照数据的主键以一定的 Hash 算法分开写到不同的文件桶中,只要 ChangeStore 和 BaseStore 都按照相同的规则来分桶,则只有相同文件桶内的文件需要进行 Join 关联。通过在数据写入时提前进行数据分桶能大大提高数据关联的性能。

图片

随着表中的数据不断增多,原有的 Hash 桶内的数据也会越来越多,故我们还需要一套文件桶的自动扩容机制。Mixed Format 从二叉树的结构中得到灵感,只要让 Hash 桶的个数保持为2的指数,且在扩容和缩容时只能成倍增加或减少,则能保证扩缩容前后的文件仍然保持局部关联,而无需对所有数据进行重写。

图片

上图是在 TPC-H 测试场景下,Iceberg 和 Mixed Format 分别在开启和关闭 Amoro Self-optimizing 情况下的分析性能测试结果。可以看到在开启 Self-optimizing 的情况下,Mixed Format 的分析性能略好于 Iceberg,但是在关闭 Self-optimizing 的情况下,Iceberg 的分析性能急剧下降,且在超过1个小时后基本不可用,而 Mixed Format 的分析性能的下降程度远低于 Iceberg。

冲突自动解决

当并发写入产生冲突时,系统无法判定应该最终保留哪个写入的数据,故只能拒绝后提交的事务。以一个同步数据库数据到数据湖的场景为例,实时任务在不断通过 CDC 同步数据到数据湖的同时,此时需要查询源端数据库的数据对已经完成同步的数据进行批量修正:

图片

实时任务先通过快照 S1 写入了 (id=1, name=join) 的数据,并在快照 S2 中将数据修正成 (id=1, name=john),离线更新任务在 S2 提交前开始进行更新并且在 S3 提交后尝试提交 S4',但由于 S4' 提交的数据与 S2 中 update id=1 的数据产生了冲突,故 S4' 提交失败。

但是如若用户预先定义了冲突解决的规则,那系统是能够按照预先设定的规则来判断最终应该保留谁写入的数据,进行自动的冲突解决,自然就能允许并发写入了。Mixed Format 根据这个思路允许用户提前在表上定义数据的冲突解决规则,允许并发写入,并在产生冲突时按照冲突解决规则保留最终满足用户预期的数据。并发解决规则可以是“按照数据里的某个版本字段来判断”,这样即使产生了并发写入,也只会保留版本更大的数据。但是并不是所有的表都有一个合适的字段用作版本字段,这种情况下 Mixed Format 设计了一套全局事务机制为数据自动生成版本信息,以找到一种更通用的冲突解决方案。

图片

以上面的流批并发写入的场景为例,实时任务每次写入都会生成递增的事务 ID(T1、T3-T6),保证后面写入的数据能够覆盖之前的数据。批量更新任务在开始事务时分配了全局事务 ID T2,批量更新任务在 T4 后提交成功,但其写入的数据只会覆盖 T1 及之前的数据, T3-T4 写入的数据不会被覆盖,最终保证了数据与源端保持一致。

在 Mixed Format 的实际实现里,全局的事务 ID 取的是 ChangeStore 上快照的 Data Sequence Number,这种依赖 Iceberg 本身机制分配全局事务 ID 的方案避免了依赖一个单点服务,提升了系统的可用性。

Mixed Hive Format

为了让用户历史的 Hive 表能够更轻量地升级到 Mixed Format,Amoro 设计了 Mixed-Hive Format。Mixed-Hive Format 的结构如下:

图片

Mixed-Hive Format 的结构与 Mixed-Iceberg Format 的结构非常相似,不同的是 BaseStore 不再是一张纯 Iceberg 表,而是一张同时兼容 Iceberg 和 Hive 元数据的表。具体来说 BaseStore 在 Hive MetaStore 上的元数据会保持和升级前一模一样,这样能在升级之后仍然能 100% 兼容以往的平台、工具和任务。当然 BaseStore 内的文件也同时会使用 Iceberg Metadata 进行索引和管理,以复用 Iceberg 包括 ACID 在内的强大功能。

在 ChangeStore 的数据通过 Self-optimizing 合并入 BaseStore 后会先缓存在 Hive Location之外,等到 Full Optimizing 触发时再对文件进行重写并最终放入 Hive Location 之内。Hive Location 下的文件才能通过 Hive Connector 直接访问到,也就是 Mixed-Hive Format 内 Hive 原生读的延迟由 Full optimizing 的触发间隔控制,一般控制在在一小时到一天之间。当然如果使用了 Mixed-Hive Format 自己的 Connector 来访问这张表,通过 Merge-On-Read 技术就能读到分钟级延迟的数据了。

04 总结与未来规划

Amoro 在 Apache Iceberg 的基础上设计了 Mixed Format,使用数据自动分桶、冲突自动解决等技术解决了“实时湖仓”与“流批一体”场景下的一些特殊需求。网易内部和社区用户基于 Amoro Mixed Format 在 CDC 等场景积攒了大量实践,后续会有更多文章分享不同用户使用 Mixed Format 的实践。如果在你的使用场景下也有类似需求,那我建议你可以试试 Mixed Format。

未来 Amoro 还将在 Mixed Format 上做更进一步的尝试,包括

  • 工具增强:社区正在推进实现将用户已有的 Iceberg Format 表一键升级为 Mixed Format 表,同时提供回滚为 Iceberg Format 表的能力。这样能进一步减少 Mixed Format 的试用成本,体现 Mixed Format 对 Iceberg 的兼容性。

  • 物化视图:Mixed Format 本质是将“变更数据”、“合并后数据”与“合并过程”三者拆开,这样三者都能进行更多的扩展。例如合并过程方面,现阶段在主键更新场景下,合并过程为用新的数据覆盖老的数据,如果实现了支持聚合函数的合并过程,则能实现聚合键的功能,进一步扩展更多的合并过程,则能实现更通用的物化视图功能。


关于 Amoro 的更多资讯可查看:

官网:https://amoro.netease.com/

源码:https://github.com/NetEase/amoro

作者:周劲松

编辑:Viridian

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值