Dinky 和 Flink CDC 在实时整库同步的探索之路

摘要:本文整理自 Dinky 社区负责人,Apache Flink CDC contributor 亓文凯老师在 Flink Forward Asia 2024 数据集成(二)专场中的分享。主要讲述 Dinky 的整库同步技术方案演变至 Flink CDC Yaml 作业的探索历程,并深入讲解Flink CDC Yaml的一些细节能力。其主要分为三个部分:

1、起源

2、探索

3、未来

01.起源

1.1 数据集成的背景

本次分享围绕数据集成,它也是 Flink CDC Yaml 作业的出现背景。在 Dinky 的众多用户中,我们总结出以下在传统的数据集成方案中普遍会遇到的问题:需要将业务库中的业务数据同步到分析库中,起到解耦分析的作用,一般有三点要求。要求数据必须一致、链路要求稳定、数据时效性尽可能要高。

1.2 传统数据集成方案

在传统的数据集成方案中可以通过离线和实时两条链路进行,离线通常会选择开源的方案 DataX 或 Sqoop 来做一些快照同步,实时方案会根据数据库类型进行选择,例如 Mysql 数据库采用 Debezium 或 Canal 实现增量同步,但是最终在分析库中是两种表的存在形式。需要在下一步数据加工治理过程中先将快照表和增量表合并为一张表,才能进行完整的一个统计分析。这样会造成一个影响:全量和增量割裂,并且使用到的技术组件和链路较长,导致整体的数据时效性偏低。

Flink CDC 自发布以来,其中 2.0 版本带来了重大更新,尤其是增量快照方法。可以将数据库中的全量数据和增量实时数据合并,保证数据的一致性。其次采用 Flink CDC 时可以不需要部署 Debezium 或 Kafka 等其他组件,只需要 Flink CDC 一个组件就可以完成从业务库到分析库的实时一致性快照的同步。数据链路缩短,数据时效性比传统的方案高。

1.4 数据集成面临的挑战------整库同步

在去年经常会遇到一个场景:Flink CDC 在大面积使用的情况下,业务比较多,分析需求会逐步增长,所以构建了一个整库同步的作业,将业务库中的全部表或部分表同步到分析库中。以往在技术瓶颈的限制下,开发方式是通过 Flink CDC 的 SQL 来完成对每一张表的处理。例如源库中有一千张表,可能就需要开发一千个 Flink SQL 的作业,每一个作业会建立一个单独的数据源连接,会消耗额外的连接数,Binlog 也会重复读取。整个过程中会产生大量的 Flink 流作业,导致 Flink 集群越来越难以运维。这是遇到的第一个挑战。

1.5 数据集成面临的挑战------模式演变

第二个挑战是模式演变的问题。业务库如果发生表结构变更,下游分析库无法感知到。如果下游库无法感知进行同步变更,此时数据链路仍然在进行同步,就会丢失一些新增的数据信息。例如增加了一个 age 列,如果下游库没有同步更新表结构就会丢失最新列的一些数据。

1.6 用户渴望------端到端数据集成

用户所渴望的是可以有全增量的自动切换、元数据可以自动发现、表结构可以自动同步、整库同步只需要一个链接一个作业、在开发过程中只需一个 SQL 完成。

02.探索

2.1整库同步的探索之路

先介绍一下 Dinky。Dinky 是一个以 Apache Flink 为内核构建的开源实时计算平台,具备实时应用的作业开发、数据调试及运行监控能力,助力实时计算高效应用。

2.2 Dinky的介绍

Dinky 可以连接众多的开源框架,例如 Paimon、Hudi、Iceberg 等其它数据库和数据湖。Dinky 主要有两个核心能力,第一是实时计算 IDE,可以对 Flink 作业、Flink SQL 和整库同步作业进行调试,在 IDE 界面上实时展现任务的流数据,便于排查数据问题。第二是提供实时运维的能力,将 Flink 集群进行统一管理,可以对任务进行实时监控,触发自定义的告警规则时,进行多渠道的告警通知。

对于整库同步,Dinky 还提供 CDC Source 的方案。此分享将对两个方案进行对比。

Dinky 在实现 Flink CDC 整库同步的探索上,通过实现一个 EXECUTE CDCSOURCE 的语法,让用户通过正则表达式等其他配置来完成整库同步任务的定义,来实现全增量自动切换、元数据自动发现、结构变更自动同步、只用一个库连接、一句 SQL 部署作业。此外,还支持写入各种数据源、支持各种部署模式,这些额外能力在一定程度上缓解了 Flink CDC 在各种连接器 Source 和 Sink 上的不足。

2.4 Dinky CDC Source 整库同步数据链路

Dinky CDC Source 整库同步数据链路分析如下。在分库分表的场景下,由 Source 节点将 Binlog 日志解析成 Debezium 格式的 Json,将 Json 数据按表名和主键进行分区,来支持下游多并行度的处理。下游按表名合并后进行分发,此处的表名合并主要用于分库分表的场景,可以通过一些正则表达式和条件来指定分库分表的规则。Route 可以将符合规则的表合并为一张表进行输出。按表名合并后,会为下游每一张表产生对应算子。示例中有两张表,就可以产生 Table1 和 Table2 两条路线进行输出。该 Pipeline 的实现主要基于 Process 和 Data Stream 来开发。为了适配更多的连接器,例如适配输出到 Hudi 或 MySQL 数据库,在最后一步 Data Sink 时也支持使用 Flink 的 SQL API 进行,这样就可以兼容所有的 Flink SQL API,最终实现将 Flink CDC 支持的数据源整库同步到任意一个 Flink SQL API 实现的数据库。

由于基于 Data Stream 开发,所以模式演变比较受限,会导致模式演变受下游数据库影响。例如 Doris Sink 支持下游演变,需要将数据流转换为字符串的格式。所以我们可以进行一个链路的复用,将前面的 Debezium json 进行相关处理,到最后环节序列化成字符串,将字符串传输给 Doris Sink,由 Doris Sink 进行模式演变的处理。此时可能存在问题:当有多并行度任务时,例如多并行度为 2 时有两个 Doris Sink 写入同一张表,会存在模式演变时数据的丢失,一个算子在进行模式演变,另一个算子在进行数据写入,这就是一个弊端。所以只能在并行度为 1 时正常使用。

2.5 Dinky CDC Source的局限性

Dinky CDC Source 存在一些局限性。

首先不支持自定义转换,Dinky CDC Source 只支持宽容数据类型的转换。

第二,由之前的算子拓扑图可以发现,面对一些表同步时会构建大量的算子节点,这样作业会非常庞大,从而会导致作业的恢复成本增加。

第三点是模式演变受限。本身框架不支持模式演变,需要由下游 Sink 连接器独立实现。

2.6 Dinky CDC Source整库同步的数据转换探索

在 Dinky CDC Source 整库同步的数据转换探索上,由于下游可以支持 Table API 的使用,所以下游可以直接使用 Flink CTAS 语法,通过 Select 语句定义转换,本质上使用 Flink SQL 的处理来进行。但是仍然会构建大量算子节点,且不支持模式演变。

去年 Flink CDC 3.0 发布,并贡献给 Apache 孵化器。由于 Dinky CDC Source 存在严重的架构瓶颈,只能满足一些特定情况下的整库同步场景。经过调研后发现 Flink CDC YAML(Flink CDC Pipeline)作业完全重构了整库同步的底层设计,支持模式演变和数据转换的能力。

Flink CDC YAML 作业的架构主要核心是基于Flink 的运行环境来完成自定义算子的编排。在设计数据流时摒弃了 Flink SQL 的数据流,自定义了一些高效的数据结构。通过 Data Source、Data Sink、Schema Registry、Router 和 Transformer 五个算子来完成整个作业的编排。上游通过 Flink CDC Cli 和 Yaml 脚本来指定作业细节,完成整库同步作业定义。

这是一张 Flink CDC Pipeline 的数据链路图,模式演变、数据转换和分库分表三种场景结合使用。在经历每个算子节点计算后,流数据的结构会发生变化。首先通过 Data Source 节点读取到原始的 Schema 结构,使用数据转换时引入 PreTransform 和 PostTransform 两个算子。PreTransform 对无关的列进行删除,裁剪后 Schema 更加简洁。PostTransform 进行一些计算及投影等能力,包括两部分,第一部分添加计算列,第二部分添加过滤条件,实现整库同步链路中自定义数据转换的能力。数据在投影后字段会增加,通常投影 Schema 会比之前的结构更宽。其中链路图中的数据流长度可以反映出 Schema 大小的变化。下一步在 Schema operator 算子中对分库分表场景下的一些结构进行进一步合并。不同的库表可能会存在表结构不同、数据类型不同的问题。为了保证数据可以完整输出到下游目标库,通过对分库分表场景的一些数据进行宽容处理,最终合并后的 Schema 大于等于投影后的 Schema 结构。此处在触发模式演变时,通过对 DataChangeEvent 进行阻塞处理,保证下游数据库数据正确一致性。解决了 Dinky CDC Source 在多并行度下进行模式演变的丢失部分变更数据的问题。

接下来介绍数据在 Flink CDC Pipeline 上如何变化。首先定义了一个 Transform,增加了一个计算列,使用 UDF(age_year)来计算年龄,过滤条件为保留成年人。这样一个 DEMO 可以覆盖 Flink CDC YAML 作业中 Transform 相关的核心能力。注意,进入 Data Source 后的数据不包含 Schema,此处将 Schema 和 Data 放在一起是为了方便理解数据,而下面的 Data 更接近 Flink CDC 数据的传输格式。经过 PreTransform 后,会裁剪无关的列,可以发现前面的 name 列没有被使用到,所以被裁剪。下一步 PostTransform 进行年龄的计算,其中所使用到的出生日期列,被定义为引用列,保留所有引用列。目前 Projection 所引用的两个列是 id 和 birthday。此处的 filter 可以对投影后的结果进行进一步过滤,对年龄不满足该条件的数据进行丢弃。此处输入的四条数据中有两条不满足,所以被丢弃。最后的 Data Sink 环节,会将这两条数据输出到分析库或数据湖,最终的数据形态由各个库的特性决定,例如要输出 Doris 数据库,要求主键是 id,最终实现 upsert 能力。该示例涵盖条件过滤、列投影、UDF 的使用、主键定义,可以很好在测试环境中体验和模拟 Transform 的特性。

随着整库同步作业的普及,可能会将数据清洗工作前置到整库同步作业中,提前将不合适的数据或垃圾数据进行清洗,从而使用到 Transform。

下面是 Transform 的实现细节。首先分为两部分:前置处理和后置处理。前置处理是对数据进行裁剪,消费 SchemaChangeEvent,通过 ChangeEvent 进行表结构的推导。其表结构不能在作业创建前被预先定义,在 YAML 作业中所定义的配置只是一些规则。当 YAML 作业读取到数据时会创建对应的 CreateChangeEvent,通过消费建表语句的事件来完成引用列及下游表结构的推导。此处包含主键分区键的定义,同时丢弃掉未使用的列来提升传输效率。后置的 Transform 操作是用于计算,首先推导出计算列,将计算投影到数据集中,并通过条件规则进行过滤。

2.11 Transform的表达式计算

在计算列和条件过滤中使用的是表达式。在表达式中,为了方便将 Flink SQL 作业迁移到 YAML 作业上,定义了投影规则与过滤规则,接近于 Flink SQL 原始写法,但不等于 Flink SQL。其中在表达式中处理都是对单表进行操作。为了满足 Transform 模块中进行动态的表达式计算,引入了一个新的框架 Janino。Janino 是一个轻巧的 Java 动态编译器,在 Apache Flink 中使用。同时引入 Apache Calcite 进行语法解析,也在 Apache Flink 中使用。基于这两个技术栈实现了动态表达式计算,可以在预定义的规则上结合变更的表结构来进行计算。

Transform 主要包含六大部分:投影规则、过滤规则、自定义函数、内置函数、运行时 Schema、运行时 Data。Transform 通过 Calcite 将类 SQL 的规则转换成最终的编译器脚本。具体步骤为 Calcite 将投影规则和过滤规则转换成一个 SQL 查询语句,进行语法树的解析,最终推导出 AST。由于是单表的处理任务,不需要进行相关的逻辑优化。再遍历 AST 生成对应的 Janino 的语法树,然后生成 Janino 的表达式,这样可以将 YAML 的脚本转换成一个动态的 Janino 的表达式,并且通过缓存来提升处理效率。

2.12 模式演变的机制与策略

在 Flink CDC YAML 中支持模式演变的机制与策略。该机制解决了 Dinky CDC Source 由于架构的限制不支持模式演变的缺点。提供了一些细粒度的策略和全局策略,可以进行灵活控制。例如,不要求下游进行模式演变或者要摒弃某些模式演变,可以通过这种全局策略和细粒度策略进行控制来满足多样化使用。

2.13 其他方面比较

其他方面的比较有三大点:数据结构、分库分表、输入输出。

Flink CDC Pipeline 带来一个高性能的数据结构。Dinky CDC Source 的实现基于 Flink Data Stream 实现,结果是一个宽的结构,每条数据都包含完整的 Schema 信息。在 Flink CDC Pipeline YAML 作业中,将数据结构进行压缩,将 Schema 和 data 进行分离,最终根据数据的实际内容进行分配,此处的传输效率和资源使用得到了一定提升,对事件变更进行了合并。图中左侧 Dinky CDC Source 有四条 Flink 流事件语义,而 Flink CDC 则将 Update 合并为 Before 和 After 进行统一处理,减少了需要处理的流事件数量。

Flink CDC Pipeline 具有分库分表的宽容机制。而 Dinky CDC Source 不具备该能力,虽然可以对分库分表的数据进行合并,但不具备对不同列冲突或不兼容的列进行处理,强要求表结构必须相同。Flink CDC Pipeline 作业引入一些宽容机制,可以自动打宽表结构,保证在分库分表合并过程中为用户保留更多的数据和信息,不至于丢失。

下面案例第一个是新增列,两个分表的结构完全一致,但是之后其中一张表的结构增加了一个地址列,此时 Flink CDC Pipeline 会自动为旧数据补充上值为空的地址列。第二个是修改列,列类型的变更有一些兼容机制,保证列类型进行宽容的转换。第三个删除列可以自动删除数据进行过滤。

2.15 Source与Sink

Dinky CDC Source 架构基于 Data Stream 开发,支持所有 Flink CDC Source,支持所有 Flink SQL 的 Sink。而 Flink CDC Pipeline 支持的连接器比较少,需要二次开发。目前有很多用户使用 Dinky CDC Source 来处理 Flink CDC Pipeline 作业不支持的场景。

2.16 两者差异总结

两者差异总结如下。

  1. Dinky CDC Source 作业通过类 SQL 语句进行定义,Flink CDC Pipeline 作业通过 YAML 脚本定义。

  2. Dinky 是一个实时计算平台,拥有完善的前端 IDE 交互,所以作业通过界面进行提交。Flink CDC Pipeline 作为一个后端框架使用,提供通过脚本来启动 YAML 作业任务,但是该启动模式在生产环境中不太适用。

  3. Flink CDC Pipeline 具备完整的模式演变,Dinky CDC Source 受限于下游 Sink 连接器的实现。

  4. 分库分表方面,Flink CDC Pipeline 支持不同的表结构宽容合并。

  5. Flink CDC Pipeline 支持完整的 Transform,基于 Transform 架构,可以实现更多能力,例如调用 API 能力,后续会有一些向量计算的能力在 Pipeline 作业中进行扩展。

  6. Dinky CDC Source 的 Source 支持 Flink CDC 所有的 Source,可以理解为原生 Source,所提供的是 API Source,不是 Pipeline Source。

  7. Dinky CDC Source 的 Sink 支持所有的 Flink SQL Sink,而 Flink CDC Pipeline 支持的较少。

  8. Flink CDC Pipeline 的数据结构上具有高性能的二进制结构。

  9. Dinky CDC Source 算子节点有大量节点,而 Flink CDC Pipeline 节点非常少。

  10. 部署模式上 Dinky CDC Source 支持所有部署模式,Flink CDC Pipeline 支持少,不支持 Yarn。

  11. 由于上述的一些条件,例如数据结构、算子拓扑节点,会导致数据资源的消耗有明显差异。

由于 Dinky CDC Pipeline 作业有局限性,所以在使用过程中会有一些痛点。Dinky 在最新版本中提供了 Flink CDC Pipeline 作业,可以在 Dinky 中定义一个 EXECUTE PIPELINE 语句来定义 Flink CDC YAML 脚本配置,通过 Dinky 平台提交到 Flink 集群。同时可以解决上述提到的 CDC 的缺点:不支持 Yarn、提交方式不方便等。

在 Dinky 中使用 Flink CDC Pipeline 可以完全兼容 Flink SQL 生态管理的功能,例如托管作业状态、告警等功能。下一步会增加相关功能帮助用户调试 Flink CDC Pipeline 作业,帮助用户在页面上看到 Pipeline 作业的输出。

03.探索

Dinky CDC Source 是作为一个过渡工具来保证用户在 Flink CDC Pipeline 普及前有业务需求时使用。目前 Dinky CDC Source 已经有近百家用户在使用,未来也会为 Dinky CDC Source 添加一个 Pipeline 转换功能,将 Dinky CDC Source 转为 Flink CDC YAML 作业,帮助用户快速架构到 Flink CDC YAML 上。其次会进行一些细粒度策略,试图尝试扩展 Transform 来满足用户需求。最后探索实时湖仓的治理,同时我们的项目也在寻找 Apache 孵化器的导师。

我们会与 Flink CDC 进行紧密合作,将 Flink CDC 各种能力应用在 Dinky 上,并投入精力在 Flink CDC 上,帮助社区完成对应的一些 Transform 优化及其他场景的完善。

相关推荐
IT成长日记6 小时前
【Hadoop入门】Hadoop生态之MapReduce简介
大数据·hadoop·mapreduce
成长之路5147 小时前
【实证分析】数智化转型对制造企业全要素生产率的影响及机制探究(1999-2023年)
大数据
黑眼圈的小熊猫8 小时前
Git开发
大数据·git·elasticsearch
涛思数据(TDengine)8 小时前
虚拟表、TDgpt、JDBC 异步写入…TDengine 3.3.6.0 版本 8 大升级亮点
大数据·数据库·tdengine
goTsHgo9 小时前
Flink的 RecordWriter 数据通道 详解
大数据·flink
Romantic Rose10 小时前
你所拨打的电话是空号?手机状态查询API
大数据·人工智能
随缘而动,随遇而安10 小时前
第四十六篇 人力资源管理数据仓库架构设计与高阶实践
大数据·数据库·数据仓库·sql·数据库架构
小宋102111 小时前
Linux安装Elasticsearch详细教程
大数据·elasticsearch·搜索引擎