什么是 Flink CDC

2,062 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情

一、什么是 Flink CDC

CDC是(Change Data Capture 变更数据获取)的简称。

核心思想是,监测并捕获数据库的变动(包括数据 或 数据表的插入INSERT、更新UPDATE、删除DELETE等),将这些变更按发生的顺序完整记录下来,写入到消息中间件中以供其他服务进行订阅及消费。

Flink CDC 是 CDC(change data capture 变更数据捕获)在 Flink 的一种实现,Flink社区开发了 flink-cdc-connectors 组件,这是一个可以直接从 MySQLPostgreSQL 等数据库直接读取全量数据和增量变更数据的 source 组件。具体体现为一系列的 Flink CDC Connector,如 Mysql CDC connector,PostgreSQL connector 等。Flink CDC Connector 内嵌了 Debezium 引擎 来捕获数据变更,利用其抽取日志获取变更的能力,将changelog 转换为 Flink SQL 认识的 RowData 数据。

image.png

二、Flink CDC支持的数据源

数据源版本
MySQLDatabase: 5.7, 8.0.x , JDBC Driver: 8.0.16
PostgreSQLDatabase: 9.6, 10, 11, 12 JDBC Driver: 42.2.12
MongoDBDatabase: 3.6, 4.x, 5.0, MongoDB Driver: 4.3.1
OracleDatabase: 11, 12, 19,Oracle Driver: 19.3.0.0

三、Flink CDC的特性

功能特性

  • 支持数据库级别的快照,读取全量数据,2.0版本可以支持不加锁的方式读取
  • 支持 binlog,捕获增量数据
  • Exactly-Once
  • 支持 Flink DataStream API,不需要额外部署 Debezium 和 Kafka即可在一个 Flink 作业中完成变更数据的捕获和计算
  • 支持 Flink Table/SQL API,可使用 SQL DDL 来创建 CDC Source 表,并对表中的数据进行查询。

四、相比于 Kafka Streams ,Flink CDC 的优势

  • Flink的操作者和SQL模块都比较成熟且易于使用
  • Flink的作业可以通过调整运算器的并行度来完成,易于扩展处理能力
  • Flink支持先进的状态后端(State Backends),允许访问大量的状态数据
  • Flink提供更多的Source和Sink等。
  • Flink拥有更大的用户群和活跃的支持社区,问题更容易解决
  • Flink开源协议允许云厂商进行全托管深度定制,而Kafka Streams则只能由其自己部署和运营
  • 和Flink Table/SQL模块集成了数据库表和变化记录流(例如CDC的数据流)。作为同一事物的两面,结果是Upsert Message结构(+I表示新增、-U表示记录更新前的值、+U表示记录的更新值、-D表示删除)。

五、传统CDC和Flink CDC对比

之前的CDC架构:

image.png

以上是之前的mysql binlog日志处理流程,例如canal监听binlog把日志写入到kafka中。而Flink实时消费Kakfa的数据实现mysql数据的同步或其他内容等。

拆分来说整体上可以分为以下几个阶段。

  • mysql开启binlog
  • canal同步binlog数据写入到kafka
  • flink读取kakfa中的binlog数据进行相关的业务处理

整体的处理链路较长,需要用到的组件也比较多。Flink CDC可以直接从数据库获取到binlog供下游进行业务计算分析,从内部实现上讲,Flink CDC Connectors 内置了一套 Debezium 和 Kafka 组件,但这个细节对用户屏蔽,简单来说链路会变成这样

image.png 也就是说数据不再通过canal与kafka进行同步,而flink直接进行处理mysql的数据,节省了canal与kafka的过程。

六、基于 Flink SQL CDC 的数据同步方案实践

如下的这段 Flink SQL 代码就能完成实时同步 MySQL 中 orders 表的全量+增量数据的目的:

CREATE TABLE orders (
  order_id INT,
  order_date TIMESTAMP(0),
  customer_name STRING,
  price DECIMAL(10, 5),
  product_id INT,
  order_status BOOLEAN
) WITH (
  'connector' = 'mysql-cdc',
  'hostname' = 'localhost',
  'port' = '3306',
  'username' = 'root',
  'password' = '123456',
  'database-name' = 'mydb',
  'table-name' = 'orders'
);
 
SELECT * FROM orders