持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
一、什么是 Flink CDC
CDC是(Change Data Capture 变更数据获取
)的简称。
核心思想是,监测并捕获数据库的变动(包括数据 或 数据表的插入INSERT、更新UPDATE、删除DELETE等),将这些变更按发生的顺序完整记录下来,写入到消息中间件中以供其他服务进行订阅及消费。
Flink CDC 是 CDC(change data capture 变更数据捕获)在 Flink 的一种实现,Flink社区开发了 flink-cdc-connectors
组件,这是一个可以直接从 MySQL
、PostgreSQL
等数据库直接读取全量数据和增量变更数据的 source 组件。具体体现为一系列的 Flink CDC Connector,如 Mysql CDC connector,PostgreSQL connector 等。Flink CDC Connector 内嵌了 Debezium 引擎
来捕获数据变更,利用其抽取日志获取变更的能力,将changelog 转换为 Flink SQL 认识的 RowData 数据。
二、Flink CDC支持的数据源
数据源 | 版本 |
---|---|
MySQL | Database: 5.7, 8.0.x , JDBC Driver: 8.0.16 |
PostgreSQL | Database: 9.6, 10, 11, 12 JDBC Driver: 42.2.12 |
MongoDB | Database: 3.6, 4.x, 5.0, MongoDB Driver: 4.3.1 |
Oracle | Database: 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架构:
以上是之前的mysql binlog日志处理流程,例如canal监听binlog把日志写入到kafka中。而Flink实时消费Kakfa的数据实现mysql数据的同步或其他内容等。
拆分来说整体上可以分为以下几个阶段。
- mysql开启binlog
- canal同步binlog数据写入到kafka
- flink读取kakfa中的binlog数据进行相关的业务处理
整体的处理链路较长,需要用到的组件也比较多。Flink CDC可以直接从数据库获取到binlog供下游进行业务计算分析,从内部实现上讲,Flink CDC Connectors
内置了一套 Debezium 和 Kafka 组件,但这个细节对用户屏蔽,简单来说链路会变成这样
也就是说数据不再通过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