Flink 1.11 发布了支持 MySQL CDC(Changelog Data Capture) 可以直接解析 Canal / Debezium 格式的 MySQL Binlog

对于实时处理程序,MySQL 的 Binlog 是很重要的数据源(上一个项目几乎所有实时数据都是来自业务系统的数据库,
也就是MySQL,算上分库分表,接了上千个 MySQL 表的 binlog)

Flink 1.11 的 CDC 发布之后,第一时间就尝试了一下 Canal 的 binlog 格式,不过感觉一般,还要部署解析的 Canal / Debezium,我们自己开发的解析 MySQL binlog 的组件,
比 Cancel 适合更适合我们,就放弃继续研究这个东西了

最近一段时间,也看到很多同学在社区提起 Flink CDC ,一直以为是类似于 Stateful Functions 的 Flink 组件,今天看下下,才发现是云邪大佬开源的 Flink-cdc-connector

GitHub 地址: https://github.com/ververica/flink-cdc-connectors

Flink-cdc-connector 就是个 CDC 组件,可以跳过 Canal / Debezium 等解析 Binlog 的工具,直接获取 MySQL 的 Binlog,转换成 Flink 的流表

Flink-cdc-connector 目前支持 MySQL 和 Postgres 两种数据库,详情查看 GitHub

----------------进入主题--------------------------

这次是 cdc 的demo,所以需要将数据写到 MySQL 中, 所以我就直接起了两个任务:

1、 kafka to mysql
2、 mysql cdc to kafka

## kafka to mysql

数据还是使用的之前从天池公开数据集中下载的 user_log,kafka source 没什么好说的,直接从 kafka 读取数据,使用 jdbc sink 写入到 mysql 中

mysql 表结构:

create table user_log
(
    id          int auto_increment primary key,
    user_id     varchar(20) not null,
    item_id     varchar(20) null,
    category_id varchar(20) null,
    behavior    varchar(10) null,
    ts          datetime    null
)
comment '天池公开数据集-淘宝用户数据';

flink jdbc sink 表如下:

CREATE TABLE mysql_table_venn_user_log_sink (
  user_id STRING
  ,item_id STRING
  ,category_id STRING
  ,behavior STRING
  ,ts timestamp(3)
) WITH (
  'connector' = 'jdbc'
  ,'url' = 'jdbc:mysql://venn:3306/venn'
  ,'table-name' = 'user_log'
  ,'username' = 'root'
  ,'password' = '123456'
  ,'sink.buffer-flush.max-rows' = '100' -- default
  ,'sink.buffer-flush.interval' = '1s'
  ,'sink.max-retries' = '3'
);


写入数据如下:

 

 ## mysql cdc to kafka

这个要稍微麻烦一点,由于 cdc source 是 upsert 的,并且不支持 WindowGroupAgg,所以使用了自己开发的 kafka upsert sink(注意: 代码中直接过滤了 delete 流)

The main method caused an error: GroupWindowAggregate doesn't support consuming update and delete changes which is produced by node TableSourceScan(table=[[default_catalog, default_database, cdc_mysql_venn_user_log]], fields=[id, user_id, item_id, category_id, behavior, ts])
        at org.apache.flink.client.program.PackagedProgram.callMainMethod(PackagedProgram.java:302)

源码: KafkaUpsertTableSink

@Override
public DataStreamSink<?> consumeDataStream(DataStream<Tuple2<Boolean, Row>> dataStream) {

    final SinkFunction<Row> kafkaProducer = createKafkaProducer(
            topic,
            properties,
            serializationSchema,
            partitioner);

    // todo cast DataStream<Tuple2<Boolean, Row>> to DataStream<Row>
    return dataStream
            .flatMap(new FlatMapFunction<Tuple2<Boolean, Row>, Row>() {
                @Override
                public void flatMap(Tuple2<Boolean, Row> element, Collector<Row> out) throws Exception {
                    // upsertStream include insert/update/delete change, true is upsert, false is delete
                    // create new row include upsert message
                    if (element.f0) {
                        out.collect(element.f1);
                    } else {
                        System.out.println("KafkaUpsertTableSinkBase : retract stream f0 will be false");
                    }
                }
            })
            .addSink(kafkaProducer)
            .setParallelism(dataStream.getParallelism())
            .name(TableConnectorUtils.generateRuntimeName(this.getClass(), getFieldNames()));
}

下面来看 cdc 的 sql:

-- creates a mysql mysql table source
drop table if exists cdc_mysql_venn_user_log;
CREATE TABLE cdc_mysql_venn_user_log (
  id varchar
  ,user_id VARCHAR
  ,item_id VARCHAR
  ,category_id VARCHAR
  ,behavior VARCHAR
  ,ts TIMESTAMP(3)
  ,proc_time as PROCTIME()
  ,PRIMARY KEY (id) NOT ENFORCED
) WITH (
 'connector' = 'mysql-cdc',
 'hostname' = 'venn',
 'port' = '3306',
 'username' = 'root',
 'password' = '123456',
 'database-name' = 'venn',
 'table-name' = 'user_log'
);

-- kafka sink
drop table if exists cdc_mysql_user_log_sink;
CREATE TABLE cdc_mysql_user_log_sink (
  id varchar
  ,user_id VARCHAR
  ,item_id VARCHAR
  ,category_id VARCHAR
  ,behavior VARCHAR
  ,ts TIMESTAMP(3)
) WITH (
  'connector.type' = 'upsertKafka'
  ,'connector.version' = 'universal'
  ,'connector.topic' = 'cdc_mysql_user_log_sink'
  ,'connector.properties.zookeeper.connect' = 'venn:2181'
  ,'connector.properties.bootstrap.servers' = 'venn:9092'
  ,'format.type' = 'json'
);

-- sink to kafka
insert into cdc_mysql_user_log_sink
select id, user_id, item_id, category_id, behavior, ts
from cdc_mysql_venn_user_log;

注: flink cdc connector 表不支持定义 watermark

java.lang.UnsupportedOperationException: Currently, defining WATERMARK on a changelog source is not supported.

删除mysql 表数据时,taskmanager 打印 delete message:

 

 

完整代码请查看: GitHub https://github.com/springMoon/sqlSubmit

拓展: Flink SQL CDC 上线!我们总结了 13 条生产实践经验 https://mp.weixin.qq.com/s/Mfn-fFegb5wzI8BIHhNGvQ

欢迎关注Flink菜鸟公众号,会不定期更新Flink(开发技术)相关的推文

 

posted on 2020-09-27 20:03  Flink菜鸟  阅读(10333)  评论(0编辑  收藏  举报