一、背景说明

所谓CDC:全称是 Change Data Capture ,在广义的概念上,只要能捕获数据变更的技术,我们都可以称为 CDC 。通常我们说的 CDC 技术主要面向数据库的变更,是一种用于捕获数据库中数据变更的技术。

目前实时链路对于数据的处理是大多数使用的方案是通过工具,对业务数据日志的监控(如canal/maxwell),并连接到kafka,实现对业务数据的实时获取,在实时数仓架构上,ods层一般也会设计在kafka(数据入湖另外说),参考下面图1。而通过FlinkCDC则可以在确保数据一致性的前提下,绕过消息中间组件,Flink实现对数据的直接处理,减少数据的流转链路,另外,由于还支持分布式处理,因此可以获得比canal等组件更高的效率,流程如下面图2。



二、代码部分

关于版本兼容一点说明:使用StreamAPI的话,1.12的版本是支持CDC2.0,如若使用FlinkSQL,需按照官方指定的版本,使用1.13

/**
* @Author: Rango
* @Date: 2021/09/12/下午10:25
* @Description: FlinkCDC监控MySQ,DataStream写法,demo不写checkpoint
*/
public class flincdc {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment().setParallelism(1); DebeziumSourceFunction<String> mysqlSource = MySqlSource.<String>builder()
.hostname("localhost")
.port(3306)
.username("root")
.password("123456")
.databaseList("test_cdc")
.tableList("test_cdc.cdc_flink") //必须加库名
.deserializer(new myDeserializationSchema()) //自定义反序列化
//.deserializer(new StringDebeziumDeserializationSchema()) //原反系列化器
.startupOptions(StartupOptions.initial())
.build(); DataStreamSource<String> mysqlDS = env.addSource(mysqlSource);
mysqlDS.print();
env.execute();
}
}
//自定义反序列化器
class myDeserializationSchema implements DebeziumDeserializationSchema<String> {
/*
期望输出效果
{
db:数据库名
tb:表名
op:操作类型
befort:{} 数据修改前,create操作没有该项
after:{} 数据修改后,delete操作没有该项
}
*/
public void deserialize(SourceRecord sourceRecord, Collector<String> collector) throws Exception { JSONObject result = new JSONObject(); String[] split = sourceRecord.topic().split("\\.");
result.put("db",split[1]);
result.put("tb",split[2]); //获取操作类型
Envelope.Operation operation = Envelope.operationFor(sourceRecord);
result.put("op",operation.toString().toLowerCase()); Struct value =(Struct)sourceRecord.value();
JSONObject after = getValueBeforeAfter(value, "after");
JSONObject before = getValueBeforeAfter(value, "before"); if (after!=null){result.put("after",after);}
if (before!=null){result.put("before",before);} collector.collect(result.toJSONString());
} public JSONObject getValueBeforeAfter(Struct value,String type){
Struct midStr = (Struct)value.get(type);
JSONObject result = new JSONObject();
if(midStr!=null){
List<Field> fields = midStr.schema().fields();
for (Field field : fields) {
result.put(field.name(),midStr.get(field));
}
return result;
}return null;
} public TypeInformation<String> getProducedType() {
return BasicTypeInfo.STRING_TYPE_INFO;
}
}

效果展示:

#监控的MySQL数据库对应的表结构及数据如下:
mysql> select * from test_cdc.cdc_flink;
+------+----------+--------+
| id | name | sex |
+------+----------+--------+
| 1001 | zhangsan | female |
| 1002 | lisilsi | male |
+------+----------+--------+
2 rows in set (0.00 sec) #命令行提交jar包
./bin/flink run -c com.hll.flincdc FlinkCDC-1.0-SNAPSHOT-jar-with-dependencies.jar

默认 initial 模式,也就是任务启动会把数据库原有数据全打印出来。其他模式在第三部分介绍

三、2.0版本的主要优化点说明

在1.x的版本有如下提到的几个问题,而在2.0的版本,则实现了无锁读取的方式来实现一致性的保证,并且全量读取支持checkpoint,失败无需从头再开启任务。

所谓无锁读取的方式则是通过全量数据chunk切分后并行读取,通过高低水位的方式来确保全量数据一致性读取,而增量部分则是单线程汇报方式,碍于篇幅此处不做源码解读,感兴趣可以看看源码BlinlogSplit部分。

四、其他说明

  • 关于反序列那块,由于cdc直连数据库会有太多冗余信息,只提取需要内容即可,原生内容为SourceRecord对象,对内容进行对应提取即可,SourceRecord对象完整内容如下:
SourceRecord{sourcePartition={server=mysql_binlog_source}, sourceOffset={ts_sec=1631413470, file=mysql-bin.000002, pos=8281, snapshot=true}} ConnectRecord{topic='mysql_binlog_source.test_cdc.cdc_flink', kafkaPartition=null, key=Struct{id=1001}, keySchema=Schema{mysql_binlog_source.test_cdc.cdc_flink.Key:STRUCT}, value=Struct{after=Struct{id=1001,name=zhangsan,sex=female},source=Struct{version=1.5.2.Final,connector=mysql,name=mysql_binlog_source,ts_ms=1631413470946,snapshot=true,db=test_cdc,table=cdc_flink,server_id=0,file=mysql-bin.000002,pos=8281,row=0},op=r,ts_ms=1631413470950}, valueSchema=Schema{mysql_binlog_source.test_cdc.cdc_flink.Envelope:STRUCT}, timestamp=null, headers=ConnectHeaders(headers=)}
  • 关于连接source的模式,可以先看官网介绍:

initial (default): Performs an initial snapshot on the monitored database tables upon first startup, and continue to read the latest binlog.

latest-offset: Never to perform snapshot on the monitored database tables upon first startup, just read from the end of the binlog which means only have the changes since the connector was started.

简单理解,initial是默认模式,cdc任务启动后会把数据库中表原数据全打印出来,可用于历史全量历史数据的输出,而last-offset则是任务启动后,以后数据库有数据变更cdc才有数据输出,用于只关注增量数据的方式。

  • FlinkSQL的写法比较简单,上面的例子,则写法如下:
//注意sql写法必须指定表,每次只能读一张表,stramapi的方式可以监控整个库
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
tableEnv.executeSql("CREATE TABLE mysql_binlog (" +
" id INT NOT NULL," +
" name STRING," +
" sex STRING," +
" PRIMARY KEY(id) NOT ENFORCED" +
") WITH (" +
" 'connector' = 'mysql-cdc'," +
" 'scan.startup.mode' = 'latest-offset'," +
" 'hostname' = 'localhost'," +
" 'port' = '3306'," +
" 'username' = 'root'," +
" 'password' = '123456'," +
" 'database-name' = 'test_cdc'," +
" 'table-name' = 'cdc_flink')");

学习交流,有任何问题还请随时评论指出交流。

FlinkCDC 2.0使用实践体验的更多相关文章

  1. vue 2.0 开发实践总结之疑难篇

    续上一篇文章:vue2.0 开发实践总结之入门篇 ,如果没有看过的可以移步看一下. 本篇文章目录如下: 1.  vue 组件的说明和使用 2.  vuex在实际开发中的使用 3.  开发实践总结 1. ...

  2. PL/0编译器实践---后记

    花了几天时间,把清华版的<编译原理>一书中的PL/0编译器实践了一遍.颇有收获,记录如下: 理解代码的技巧,如何理解一份代码,比如这个程序,其逻辑相对于一般程序就比较复杂了,如何翻译,虚拟 ...

  3. vue2.0 开发实践总结之入门篇

    vue2.0 据说也出了很久了,博主终于操了一次实刀. 整体项目采用  vue +  vue-router +  vuex (传说中的vue 全家桶 ),构建工具使用尤大大推出的vue-cli 后续文 ...

  4. Android 7.0真实上手体验

    Android 7.0真实上手体验 Android 7.0的首个开发者预览版发布了,支持的设备只有Nexus6.Nexus 5X.Nexus 6P.Nexus 9.Nexus Player.Pixel ...

  5. AR.Drone 2.0四轴飞机体验:最好的玩具航拍器

    http://digi.tech.qq.com/a/20140513/007458.htm?pgv_ref=aio2012&ptlang=2052 AR.Drone 2.0四轴飞机体验:最好的 ...

  6. Zabbix3.0部署实践

    Zabbix3.0部署实践   Zabbix3整个web界面做了一个全新的设计. 1.1Zabbix环境准备 [root@linux-node1 ~]# cat /etc/redhat-release ...

  7. Thinkphp5.0 的实践一

    Thinkphp5.0 的实践一 tp5.0默认没有__SELF__,需要定义, define('__SELF__',strip_tags($_SERVER['REQUEST_URI'])); tp5 ...

  8. AOP框架Dora.Interception 3.0 [1]: 编程体验

    .NET Core正式发布之后,我为.NET Core度身定制的AOP框架Dora.Interception也升级到3.0.这个版本除了升级底层类库(.NET Standard 2.1)之外,我还对它 ...

  9. Spark2.1.0——Spark初体验

    学习一个工具的最好途径,就是使用它.这就好比<极品飞车>玩得好的同学,未必真的会开车,要学习车的驾驶技能,就必须用手触摸方向盘.用脚感受刹车与油门的力道.在IT领域,在深入了解一个系统的原 ...

随机推荐

  1. 安卓安装https证书

    前置条件 1 手机要设置密码 然后安装charles 证书 2 赋予 adb shell root权限(安装magisk就行) adb shell # 连接手机进入shell模式 su root # ...

  2. vue的table切换

    HTML: <div id="box"> <ul> <li v-for="(item,index) in items" v-tex ...

  3. 从net到java:java快速入门

    学习java那是不可能的,到为什么不学习一下呢.仅为总结.希望自己在不久的将来能书写优美的java程序.加油!奥利给 1.注释 注释的重要性不言而喻,我们不管写什么代码注释必不可少,那么java的注释 ...

  4. MarkDown语法(Typora软件为例)

    Hello    !我又来了 这篇文章主要给大家讲一下MarkDown的一些基础语法,MarkDown语法是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML( ...

  5. C# 为什么你应该更喜欢 is 关键字而不是 == 运算符

    前言 在C# 进行开发中,检查参数值是否为null大家都用什么?本文介绍除了传统的方式==运算符,还有一种可以商用is关键字. C# 7.0 中 is 关键字的使用 传统的方式是使用==运算符: if ...

  6. Rancher v1.6.29 Docker单节点部署

    前言: Docker镜像中心,有两个版本的rancher(1.X),镜像名称为:rancher/server,而rancher(2.X)的镜像名称是rancher/rancher 去daocloud官 ...

  7. filter,interceptor,controllerAdvice,aspect,controller执行顺序

    1.filter,这是java的过滤器,和框架无关的,是所有过滤组件中最外层的,从粒度来说是最大的. 配置方式,有直接实现Filter+@component,@Bean+@configuration( ...

  8. git 切换分支 本地代码失踪找回办法

    解决方案: https://blog.csdn.net/hupoling/article/details/79017382 主要步骤: git reflog 然后找到之前commit的分支 git c ...

  9. SpringBoot开发十五-发布帖子

    需求介绍 使用 AJAX 异步通信实现网页能够增量的更新呈现到页面上而不需要刷新整个页面. 现在基本上都是服务器返回 JSON 字符串来解析 代码实现 使用 JQuery 发送 AJAX 请求. 首先 ...

  10. Java协程编程之Loom项目尝鲜

    前提 之前很长一段时间关注JDK协程库的开发进度,但是前一段时间比较忙很少去查看OpenJDK官网的内容.Java协程项目Loom(因为项目还在开发阶段,OpenJDK给出的官网https://ope ...