来源:Apache Flink
摘要:本文整理自字节跳动基础架构工程师李国君,在 Streaming Lakehouse Meetup 的分享。幸福里业务是一种典型的交易、事务类型的业务场景,这种业务场景在实时数仓建模中遇到了诸多挑战。本次分享主要介绍幸福里业务基于 Flink & Paimon 构建流式数仓的实践经验,从业务背景、流批一体数仓架构、实践中遇到的问题和解决方案,借助 Paimon 最终能拿到的收益,以及未来规划方面进行介绍。
01
业务背景

首先由经纪人将已完成的代看任务提交工单,后续相应的门店经理会对该工单进行审核,在这个过程中就产生了两条数据,并将其更新到业务库的 Binlog 数据,作为实时数仓的数据源进行计算后生成数据报表或直接用于一些考核系统。其中数据报表用于展示评估一线经纪人的工作是否达标等;考核系统则用于门店经理为一线经纪人设定考核任务量的工作系统,通过任务量标准自动反馈奖励等。因此在以上应用的实时数仓建模上,我们发现房产类业务有两个典型的特点:
准确性要求 100%,不能有数据丢失和重复的情况发生。
需要全量计算,增量数据在 MQ 留存时间有限,需要拿到全量数据 View 进行计算。
实时数仓建模特点





为什么选择 Paimon
基于以上存在的痛点,我们考虑希望通过 Flink 生态搭建 Steaming Lakehouse 的组合来解决原始链路上的问题,如上图所示,原始链路存在的问题有:
存储异构,Base+Delta 数据难对齐;
去重引入非确定性计算和大状态;
血缘关系复杂 & 数据订正结果回退暴露给用户。
对应解决原始链路的问题,我们选择了 Paimon:
流批一体的存储可以以统一 Table 对外输出,实时和离线数据可以存储到一张 Paimon 表中,直接解决了对齐的问题;
不需要去重,Changelog Producer 代替状态算子,同时支持在存储上产生完整的 Log,并将其持久化代替原有链路上的状态算子;
血缘管理 & 数据一致性管理,支持无感知数据订正。
02
流式数仓实践

首先介绍流式数仓实践过程中的架构设计,如下图所示:
存储层选用了 HDFS 或 S3 的对象存储作为存储底座,选用 Paimon 作为统一的 Table 抽象;
计算层选用 Flink 同一的技术栈,统一了流批计算;
数据管理层实现了 Table 的血缘管理和数据的血缘管理,基于这样的血缘管理可以做到数据一致性,血缘管理可以用于数据溯源的需求,为数据质量提供保障。
数据一致性管理,流批一体 ETL 数据管理。在多表一致性联调的时候,可以自动对齐数据,不需要开发人员手动对齐。


在完成上述 Streaming Lakehouse 实践落地后总结了如下收益:
简化开发流程
流批一体存储可以解决实时和离线存储异构的问题;
减少业务入侵,移除去重算子,解决非确定性计算。
提升运维体验
中间数据可查;数据可追溯;
血缘关系 & 多表一致性,增强了多表关联调试能力,并且可以做到数据订正无感知。
减少状态量
Changelog 持久化,可以减少30%的状态量。
在实践过程中,除了获得了不少收益,也同样遇到了新的问题,主要包括两个:
数据新鲜度差:端到端的延迟变化为分钟级,数据新鲜度降低; 小文件问题:一些小文件可能会影响读写性能。
03
流式数仓的调优
端到端延迟调优

分析整个流程,可以得出两个结论:
数据可见性与 Checkpoint 绑定。更严格的说是一个周期的数据可见性与 Checkpoint 周期严格绑定。
Checkpoint 周期 = Checkpoint interval + Checkpoint latency。Checkpoint interval 是 Checkpoint 触发的频率;Checkpoint latency 是整个完成一个 Checkpoint 所需的耗时。

Checkpoint Latency 优化可以分为几个方向进行:
Log-Based 增量 Checkpoint
减少状态量
利用 Flink 高版本的一些特性,如 Log-based 增量 Checkpoint 的方式去优化上传阶段的耗时。
比如减少上传输数据量,那么上传耗时就会减少。
Checkpoint 持续上传
持续上传本地状态文件。
搭建独立 HDFS 集群

小文件优化


在小文件相关的问题中,决定是否产生小文件的时机和因素有以下几点:
文件生成。数据文件在磁盘上生成是有两个触发时机的,一个是 Checkpoint 的时候,它会强制把当前的 WriteBuffer 里的数据刷到磁盘上;第二个是 WriteBuffer,当它满了也会把内存里面的数据刷到磁盘上。如果把 Checkpoint Interval 调的过小,或是把 WriteBuffer 容量设置的比较小,那么数据就会更频繁的被刷到磁盘上,而产生过量的小文件。
文件划分。通过设置一些 Partition key 或 Bucket key,就决定了数据的走向,它会落在哪些文件里。比如,生产中实际数量非常小,同时又设置了过多的 Bucket,那么可以预见,一个 Bucket 可以分到的数据量一定会比较小。这个过程中也会遇到小文件问题。另外,如果设置 Partition key 或 Bucket key 不合理,可能会产生一些文件倾斜的情况,即热 Key 问题。
文件清理。Paimon 具有文件清理机制,在 Compaction 过程中会删除一些无用的文件。另外,数据由 Snapshot 管理,如果 Snapshot 过期,就会从磁盘上删除对应的数据文件。如果 Compaction 触发条件和 Snapshot 过期条件没有管理好,也会造成冗余的文件留在磁盘上。
基于以上的介绍,分享一下我们在实践过程中积累的一些小文件调优参数,见下表所示。
Checkpoint interval::推荐在 1-2 min 比较合适;
WriteBuffer 大小:推荐使用默认值,除非遇到相关问题需要调整;
业务数据量:可以根据业务数据量调节 Bucket 数,调整依据为单个 Bucket 大小在 1G 左右比较合适;
Key 的设置:可以根据实际的业务 Key 特点设置合适的 Bucket-key、Partition,以防产生热 Key 倾斜的问题;
Compaction 管理和 Snapshot 管理相关参数:推荐使用默认值,除非遇到相关问题需要调整。

经历了整个架构改造之后,我们将原有实时数仓链路做了对比,如下图可见,在很多指标上都获得了一定的收益。
端到端延迟:在原始实时数仓开启 Mini-batch 的情况下,端到端延迟没有明显退化,可以支持 1-2 min 的近实时可见;
数据排查时效性:可以从小时级提升到分钟级;
状态量节省了约 30%;
开发周期缩短约 50%。

04
未来规划

首先,秒级端到端延迟的尝试。可能会分几期来做,计划引入 Embeded Log System 来解决这个问题。长期来看,会把数据可见性与 Checkpoint 解绑; 其次,数据一致性管理。血缘关系管理和数据一致性管理这两个方面,在实际数据运维中是很有价值的; 第三,状态复用。状态复用主要是解决 Join 状态复用的问题。另外,我们希望可以做到中间状态可查; 第四,监控运维。未来当规模上去,希望可以建立监控体系,并做到指标可观测。
Q&A
Q:请问在数据源异构的情况下,是否考虑过其他入湖的技术选型?为何最终选择了 Paimon?
活动视频回顾 & PPT 获取
PC 端
建议前往 Apache Flink 学习网:
移动端
了解 Flink 和流式计算的优势 对 Flink SQL 基础能力和 Flink 实时处理特性有初步体验