FlinkCDC是一个数据集成框架,它基于数据库日志的CDC(变更数据捕获)技术实现了统一的增量和全量数据读取。结合Flink出色的管道能力和丰富的上下游生态系统,FlinkCDC可以高效地实现海量数据的实时集成。
(1)FlinkCDC使用场景
FlinkCDC可以应用在多种场景中。比如数据同步,可以将上游数据库中的数据同步至下游数据仓库、数据湖等。用户还可以借助FlinkCDCsource实现实时物化视图,结合下游Flink作业处理逻辑实现更丰富的业务场景。此外用户还可以使用FlinkCDC捕获的变更数据基于业务逻辑进行数据分发。
作为一款数据集成框架,FlinkCDC对接了非常丰富的上下游数据库、数据湖仓和消息队列等外部系统,如MySQL、PostgreSQL、Kafka、Paimon等。
(2)与传统数据集成流水线比较
一个传统的数据集成流水线通常由两套系统构成:全量同步和增量同步。其中全量同步会使用DataX、Sqoop等系统,增量同步需要使用另外一套系统,如Debezium、Canal等等。在全量同步完成后,可能还需要额外的一步合并操作将增量表和全量表进行合并,最终得到与上游一致的快照。这种架构的组件构成较为复杂,为系统维护带来了很多困难。
相比于传统数据集成流水线,FlinkCDC提供了全量和增量一体化同步的解决方案,对于一个同步任务,只需使用一个Flink作业即可将上游的全量数据和增量数据一致地同步到下游系统。此外FlinkCDC使用了增量快照算法,无需任何额外配置即可实现全量和增量数据的无缝切换。
FlinkCDC诞生于2020年7月,中间经过不断迭代优化,发布了多个大版本。2021年8月,FlinkCDC发布了2.0版本,首次为MySQLCDCsource引入增量快照算法,实现了全增量同步无缝切换。2022年11月,FlinkCDC发布2.3版本,将大多数connector对接至增量快照框架。2023年12月,FlinkCDC推出3.0版本,正式将FlinkCDC项目升级为实时数据集成框架,提供YAMLAPI,为数据同步提供端到端解决方案。
(1)FlinkCDCYAML
在FlinkCDC2.x的时代,FlinkCDC只提供一些Flinksource,用户仍然需要自己开发FlinkDataStream或SQL作业实现数据同步逻辑。如果用户对Flink不够熟悉,经常会遇到棘手的数据正确性和乱序问题。此外FlinkCDC2.x不支持schema变更,而schema变更是用户的业务系统中很常见而且很重要的场景。通过对用户使用场景的调研,我们发现绝大多数使用FlinkCDC的作业都是较为简单的数据ETL。结合上述问题,我们决定为用户提供一个全新的框架,设计一套全新的API,专注于数据同步场景。
(2)FlinkCDC整体设计
FlinkCDC基于Flinkruntime实现,因此可以充分复用Flink的资源管理和在不同环境上部署的能力。针对各种数据集成场景,FlinkCDC深度定制了多种自定义算子,如schemaoperator、router、transformer等。为了将不同的算子进行协调和组合,FlinkCDC引入了composer组件,可根据用户定义的数据同步逻辑构建Flink作业。依托于Flink丰富的生态系统,开发者只需简单地封装即可快速将现有的Flinkconnector对接至FlinkCDC。此外Flink还提供了CLI,只需一个脚本即可将用户的YAML定义使用composer构建成Flink作业,并提交至指定Flink集群。基于以上架构,FlinkCDC为数据集成用户提供schema变更同步、整库同步、分库分表同步等增强能力。
(3)FlinkCDCAPI
FlinkCDCAPI使用YAML语法定义数据同步任务,即易于开发者进行手动开发,又可以高效地使用机器进行处理。YAMLAPI针对数据集成场景设计,用户只需定义同步数据源和数据目标端即可快速搭建起一个实时同步流水线。此外用户还可以在YAML中定义routing和transformation实现自定义数据分发和变换。用户不再需要熟练掌握Flink作业开发与内部实现,即可使用FlinkCDC搭建实时数据集成流水线。
FlinkCDC提供的CLI(flink-cdc.sh)进一步简化了用户提交FlinkCDC任务的流程。用户只需执行一行命令,CDCcomposer会将source、sink、自定义CDCruntime构建成Flink任务,创建FlinkJobGraph后提交至Flink集群。
(4)FlinkCDCPipeline连接器
FlinkCDC定义了自己的数据源和目标端连接器的接口,以适配FlinkCDC内部的数据结构。FlinkCDCpipelineconnector基于Flinkconnector,只需进行简单的数据转换封装,即可快速复用现有的Flinkconnector,将其对接到FlinkCDC生态系统中。为了实现schema变更处理能力,FlinkCDC定义了MetadataAccessor和MetadataApplier,分别对源端和目标端的schema等元信息进行获取和处理,实现schema变更的实时同步。
(5)FlinkCDCSource增量快照算法
为了实现全量和增量的一体化同步,FlinkCDCsource使用增量快照算法,既实现了全增量同步的无缝切换,而且采用了无锁设计,避免全量同步时的锁表动作对上游业务的影响。在增量快照算法中,数据库的全量数据被切分为独立的数据块(chunk),分发给source的各个并发进行读取。考虑到在全量读取过程中数据还有可能发生变化,在开始读取前,source将binlog的当前位点记为低水位线(lowwatermark),在全量读取结束后再次将binlog最新位点记录为高水位线(highwatermark),随后读取高、低水位线之间的变更数据,将其合并到已读取的全量数据块中,从而构建一个与上游完全一致的数据块。在完成全部数据块的读取之后,source会根据记录的高水位线确定切换位点,实现全量和增量的无缝切换。
(6)FlinkCDC对Schema变更的支持
FlinkCDC通过定制化的schemaoperator以及schemaregistry的协调,实现对上游schema变更的实时同步。当schemaoperator感知到上游发生schema变更后,会将变更信息同步给schemaregistry,并暂停数据流的处理。schemaregistry首先插入Flush事件将下游数据全部从sink推出,在收到全部sink的确认后,通过MetadataApplier将schema变更应用在下游系统中,在完成schema变更后,schemaregistry通知schemaoperator,并恢复数据流处理,完成整个schema变更的流程。
(7)FlinkCDC对数据分发处理的支持
FlinkCDC定制了router算子,实现对变更数据的分发和合并。用户可以在YAML中使用route字段修改变更数据的目标数据库和表名,将数据同步至指定目标端,同样也可以通过指定多对一的路由规则,将多个表合并为目标端中的一张表。
(8)FlinkCDC对数据变换的支持
通过在YAML中使用transform字段,用户可以在数据流上定义投影、过滤、增加元信息列等数据变换操作,调整数据内容后同步至下游。transform使用类SQL语法,既可以让用户简单上手开发,又保留了对更多类型变换支持的可扩展性。
(9)FlinkCDC数据结构
FlinkCDC在数据流中定义了数据和schema信息的协议:
数据流以CreateTableEvent开始来描述起始schema
后续所有的DataChangeEvent需要遵循其前方的schema
当schema发生变更时,需要在数据流中发送一个新的SchemaChangeEvent以描述schema变化
这种设计的优势在于实现了数据和schema的分离,大大降低了数据的序列化成本。此外FlinkCDC为数据变更事件使用了压缩的二进制格式,进一步提升了性能。
目前FlinkCDC已经有超过160位贡献者,项目获得5k+star,1000+commit。未来FlinkCDC将着力于扩展生态,对接至更多的外部系统,如PostgreSQL、Iceberg等,并且将支持更多的schema变更类型和数据类型。另外FlinkCDC也会持续提升生产稳定性,包括对异常处理方式进行自定义配置、提升测试覆盖等等。作为ApacheFlink的子项目,FlinkCDC使用与Flink一致的贡献流程。欢迎各位用户和贡献者在Flink邮件列表中咨询和讨论,使用ApacheJIRA创建issue,在GitHub上提交PR!