flinkcdc 3.0 架构设计学习
本文将会了解到 flinkcdc3.0 版本的架构设计,从一个宏观层面来学习 flinkcdc3.0 带来的新特性这也是作者目前觉得学习一项技术的思路和方法,就是首先先把 demo 跑起来体验一下,然后整体了解一下架构设计,应用场景等,之后再去学习技术细节和源码,由浅入深的学习.文中内容有误请多多包涵,欢迎评论区或者加笔者微信指教.
一.概述
Flink CDC(Change Data Caputre) 是一个数据集成框架,底层原理是实时捕获数据库的日志来进行数据同步(比如 Mysql 的 binlog 日志).3.0 版本具有里程碑意义,Flink CDC 从捕获数据变更的数据源正式成为了以 Flink 为基础的端到端流式 ETL 数据集成框架目前 Flink CDC 3.0 有如下功能及特点 :
全增量一体化同步
无锁读取
并行读取
精确一致性语义
支持表结构变更自动同步
动态增表
整库同步
路由功能(可以实现分库分表合并的效果)
分布式
二.整体架构设计
首先 Flink CDC 的底层是基于 Flink 的,所以同步任务会运行在 Flink 集群,集群可以是 k8s,或者是 yarn,或者是 standalone 集群上,基于 Flink CDC API 提供的能力实现了流式管道,变更数据同步,Schema 变更同步,整库同步,分表同步,批处理管道等功能.
Flink CDC 3.0 架构一共分了 4 层
API : 接口层,面向终端用户,用户可以使用 yaml 文件来配置化生成数据同步作业,然后使用 Flink CDC CLI 提交作业.
Connect : 连接层,对接外部系统的连接器层,通过对现有的 CDC Source 进行封装实现对外部系统的读取和写入.
Composer : 同步任务构建层,将用户的同步任务翻译成 Flink DataStream 作业.
Runtime : 运行时层,根据数据同步场景高度定制 Flink 算子,实现 schema 变更,路由变换等高级功能.
三.核心设计解析
3.1 Pipeline Connector API 设计
管道连接器主要分成了两大部分,一个是负责读数据的 DataSource,一个是负责写数据的 DataSinkDataSource 由负责构建 Flink Source 的 EventSourceProvicer 组件和提供元数据读取的 MatadataAccessor 组件组成.DataSource 会读取外部系统的变更事件(变更的数据和 schema),然后传递给下游算子.DataSink 由负责构建 Flink Sink 的 EventSinkProveider 组件和提供目标端元数据修改的 MetadataApplier 组件构成.DataSink 会将上游的变更数据写到目标端,并且会将 schema 变更同步到目标端.
3.2 Schema Evolution 设计
源端的 schema 变更是非常常见的事,在之前的 cdc 版本中没有 schema 自动同步的功能,所以需要手工处理,非常的浪费时间,在 cdc3.0 版本中实现了该功能,具体的逻辑如下图
首先事件分为三类,数据变更事件,Schema 变更事件,Flush 事件 1.Schema operator 接收 Schema 变更消息.2.当 Schema operator 接收到有 Schema 变更事件的时候会将整个**数据流暂停,**然后向 SchemaRegistry 发送变更的信息然后等待响应.3.SchemaRegistry 确认 schema 的变更 4.Schema operator 广播 FlushEvent,然后等待 flush 的完成,这一步是要将 sink 端缓存的事件先 flush 到目标端,因为这部分数据是 schema 变更之前的数据.5.Sink 端 flush 完成后会通知 SchemaRegistry flush 完成 6.SchemaRegistry 通过 MetadataApplier 组件来将目标端的元数据修改 7.SchemaRegistry 修改完元数据后会通知 Schema operator flush 事件完成,目标端的 schema 变更也完成了.8.Schema operator 会恢复暂停的数据流,到此一个 Schema 的变更就完成了.
总体来说就是当 cdc 检测到有 schema 变更的时候,会先将数据流暂停,然后将之前 sink 端缓存的数据 flush 出去,然后修改目标端的元数据,修改完成后再恢复数据流.
3.3 整库同步设计
首先用户在配置文件中可以指定需要同步的整库,然后 SchemaRegistry 会在读取到新表后,自动在目标端建表,实现自动化整库同步.
3.4 分库分表同步设计
在后端开发中,因为考虑到数据的高效读写,所以会有将一个表拆成多个子表的设计,在数仓搭建中,经常会将这些分表合成一个表来处理.Flink CDC 3.0 的路由机制就可以实现分库分表的合并能力,也可以实现同步表的改名功能,demo 如下
3.5 高性能数据结构设计
因为 Flink 是分布式框架,各个算子可能分布在不同的机器上,所以数据的流转过程中就免不了要序列化和反序列化.为了降低这种序列化的开销,Flink CDC 3.0 优化了之前的架构,引入了一套高性能的数据结构.
1.变更数据和 Schema 信息分离 : 在之前设计中每条数据都带有 schema 信息,这就会增加额外的序列化成本,在 3.0 版本中发送变更数据前,source 会先发送 schema 信息对其进行描述并有框架追踪,所以 schema 无需绑定在每条变更数据上,降低了序列化的成本.
2.二进制存储格式 : 数据同步过程中使用二进制存储,只有在使用某个字段时(例如按主键进行分区)才会进行反序列化,进一步降低序列化成本.
四.一些思考
使用经历 : 最早使用 flinkcdc 1 版本的时候还会遇到锁表问题,有时候 dba 就会找来一顿问,很快 cdc2 版本的无锁读就来了,当时我们很快就换上了 2 版本,但是当时我们同步还是得写 stream api 程序来同步表到 doris,每次遇到加表或者 schema 变更就很头疼,得手动处理.现在 3 版本出来后对于用户来说体验一下子提升好几个档次,一个 yaml 文件直接生成一个同步任务,有条件的公司完全可以搞个可视化界面动态配置数据同步任务,然后生成 yaml 文件,然后再将任务提交.
一些感悟 : 为什么一开始设计的时候就不能设计成这种配置化的呢?这是我今天在写这篇文章的时候的一个疑惑,但是突然想到了公司前辈说过的一些话,什么样的架构才是一个最好的架构呢,三个词 : 简单,合适,演进 ,那在 cdc1.0 的时候一定也是为了满足当时的业务场景而设计的,随着用户增多,业务场景增多,那么就架构就不合适了,就要演进来达到合适.不光是架构方面,我觉得在敲代码上也是,很多时候看到一堆 si 山代码,你觉得不合理,为什么不加注释,为什么写这么多 if else 等等,但是可能当时这部分代码就是最符合当时场景的代码,工期紧张,长时间加班等等.现在觉得这些代码不合适,那么就要演进来达到合适.(所以之后就不要抱怨 si 山代码,阅读和修改 si 山代码也是一种能力,也不要抱怨架构的不合适,将不合适的架构修改成一套合适的架构也是一种能力)
一些奇思妙想 : 既然 flinkcdc 的同步任务可以做成配置化的,那么实时任务是否可以做成配置化呢?比如提前将各种算子写好,之后就是图形化界面的拖拉拽将算子组合,然后生成一个实时任务.开发人员仅需要开发各种配置化通用化的算子即可.
参考
[1] : https://ververica.github.io/flink-cdc-connectors/release-3.0/
[2] : https://zhuanlan.zhihu.com/p/673607667
评论