天空闲话 发表于 2024-7-22 18:28:17

非常钟掌握 Flink CDC,实现Mysql数据增量备份到Clickhouse [纯干货,发起

Clickhouse的优点.

[*]真正的面向列的 DBMS
ClickHouse 是一个 DBMS,而不是一个单一的数据库。它允许在运行时创建表和数据库、加载数据和运行
查询,而无需重新配置和重新启动服务器。

[*]数据压缩
一些面向列的 DBMS(InfiniDB CE 和 MonetDB)不使用数据压缩。但是,数据压缩确实进步了性能。

[*] 磁盘存储的数据
[*] 在多个服务器上分布式处理
[*] SQL支持
[*] 数据不仅按列存储,而且由矢量 - 列的部分进行处理,这使开发者能够实现高 CPU 性能
Clickhouse的缺点

[*] 没有完整的事务支持,
[*] 缺少完整的Update/Delete操作,缺少高频率、低延迟的修改或删除已存在数据的能力,仅能用于批量删
除或修改数据

[*] 聚合结果必须小于一台机器的内存巨细:
[*] 不适合key-value存储,
什么时候不可以用Clickhouse?

[*] 事物性工作(OLTP)
[*] 高并发的键值访问
[*] Blob大概文档存储
[*] 超标准化的数据
Flink CDC
=========
Flink cdc connector 消费 Debezium 里的数据,经过处理再sink出来,这个流程还是相对比较简朴的
https://img-blog.csdnimg.cn/img_convert/9515a1d2287df4e7c3e97672d2ec5eb7.png
首先创建 Source 和 Sink(对应的依赖引用,在文末)
SourceFunction sourceFunction = MySQLSource.builder()
.hostname(“localhost”)
.port(3306)
.databaseList(“test”)
.username(“flinkcdc”)
.password(“dafei1288”)
.deserializer(new JsonDebeziumDeserializationSchema())
.build();
// 添加 source
env.addSource(sourceFunction)
// 添加 sink
.addSink(new ClickhouseSink());
这里用到的JsonDebeziumDeserializationSchema,是我们自界说的一个序列化类,用于将Debezium输出的数据,序列化
public static class JsonDebeziumDeserializationSchema implements DebeziumDeserializationSchema {
@Override
public void deserialize(SourceRecord sourceRecord, Collector collector) throws Exception {
Gson jsstr = new Gson();
HashMap<String, Object> hs = new HashMap<>();
String topic = sourceRecord.topic();
String[] split = topic.split(“[.]”);
String database = split;
String table = split;
hs.put(“database”,database);
hs.put(“table”,table);
//获取操作类型
Envelope.Operation operation = Envelope.operationFor(sourceRecord);
//获取数据自己
Struct struct = (Struct)sourceRecord.value();
Struct after = struct.getStruct(“after”);
if (after != null) {
Schema schema = after.schema();
HashMap<String, Object> afhs = new HashMap<>();
for (Field field : schema.fields()) {
afhs.put(field.name(), after.get(field.name()));
}
hs.put(“data”,afhs);
}
String type = operation.toString().toLowerCase();
if (“create”.equals(type)) {
type = “insert”;
}
hs.put(“type”,type);
collector.collect(jsstr.toJson(hs));
}
@Override
public TypeInformation getProducedType() {
return BasicTypeInfo.STRING_TYPE_INFO;
}
}
这里是将数据序列化成如下Json格式
{“database”:“test”,“data”:{“name”:“jacky”,“description”:“fffff”,“id”:8},“type”:“insert”,“table”:“test_cdc”}
接下来就是要创建Sink,将数据变化存入Clickhouse中,这里我们仅以insert为例
public static class ClickhouseSink extends RichSinkFunction{
Connection connection;
PreparedStatement pstmt;
private Connection getConnection() {
Connection conn = null;
try {
Class.forName(“ru.yandex.clickhouse.ClickHouseDriver”);
String url = “jdbc:clickhouse://localhost:8123/default”;
conn = DriverManager.getConnection(url,“default”,“dafei1288”);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
connection = getConnection();
String sql = “insert into sink_ch_test(id,name,description) values (?,?,?)”;
pstmt = connection.prepareStatement(sql);
}
// 每条记录插入时调用一次
public void invoke(String value, Context context) throws Exception {
//{“database”:“test”,“data”:{“name”:“jacky”,“description”:“fffff”,“id”:8},“type”:“insert”,“table”:“test_cdc”}
Gson t = new Gson();
HashMap<String,Object> hs = t.fromJson(value,HashMap.class);
String database = (String)hs.get(“database”);
String table = (String)hs.get(“table”);
String type = (String)hs.get(“type”);
if(“test”.equals(database) && “test_cdc”.equals(table)){
if(“insert”.equals(type)){
System.out.println("insert => "+value);
LinkedTreeMap<String,Object> data = (LinkedTreeMap<String,Object>)hs.get(“data”);
String name = (String)data.get(“name”);
String description = (String)data.get(“description”);
Double id = (Double)data.get(“id”);
// 未前面的占位符赋值
pstmt.setInt(1, id.intValue());
pstmt.setString(2, name);
pstmt.setString(3, description);
pstmt.executeUpdate();
}
}
}
@Override
public void close() throws Exception {
super.close();
if(pstmt != null) {
pstmt.close();
}
if(connection != null) {
connection.close();
}
}
}
完整代码案例:
package name.lijiaqi.cdc;
import com.alibaba.ververica.cdc.debezium.DebeziumDeserializationSchema;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import io.debezium.data.Envelope;
import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import com.alibaba.ververica.cdc.connectors.mysql.MySQLSource;
import org.apache.flink.util.Collector;
import org.apache.kafka.connect.source.SourceRecord;
import org.apache.kafka.connect.data.Field;
import org.apache.kafka.connect.data.Schema;
import org.apache.kafka.connect.data.Struct;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.HashMap;
public class MySqlBinlogSourceExample {
public static void main(String[] args) throws Exception {
SourceFunction sourceFunction = MySQLSource.builder()
.hostname(“localhost”)
.port(3306)
.databaseList(“test”)
.username(“flinkcdc”)
.password(“dafei1288”)
.deserializer(new JsonDebeziumDeserializationSchema())
.build();
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 添加 source
env.addSource(sourceFunction)
// 添加 sink
.addSink(new ClickhouseSink());
env.execute(“mysql2clickhouse”);
}
// 将cdc数据反序列化
public static class JsonDebeziumDeserializationSchema implements DebeziumDeserializationSchema {
@Override
public void deserialize(SourceRecord sourceRecord, Collector collector) throws Exception {
Gson jsstr = new Gson();
HashMap<String, Object> hs = new HashMap<>();
String topic = sourceRecord.topic();
String[] split = topic.split(“[.]”);
String database = split;
String table = split;
hs.put(“database”,database);
hs.put(“table”,table);
//获取操作类型
Envelope.Operation operation = Envelope.operationFor(sourceRecord);
//获取数据自己
Struct struct = (Struct)sourceRecord.value();
Struct after = struct.getStruct(“after”);
if (after != null) {
Schema schema = after.schema();
HashMap<String, Object> afhs = new HashMap<>();
for (Field field : schema.fields()) {
afhs.put(field.name(), after.get(field.name()));
}
hs.put(“data”,afhs);
}
String type = operation.toString().toLowerCase();
if (“create”.equals(type)) {
type = “insert”;
}
hs.put(“type”,type);
collector.collect(jsstr.toJson(hs));
}
@Override
public TypeInformation getProducedType() {
return BasicTypeInfo.STRING_TYPE_INFO;
}
}
public static class ClickhouseSink extends RichSinkFunction{
Connection connection;
PreparedStatement pstmt;
private Connection getConnection() {
Connection conn = null;
try {
Class.forName(“ru.yandex.clickhouse.ClickHouseDriver”);
String url = “jdbc:clickhouse://localhost:8123/default”;
conn = DriverManager.getConnection(url,“default”,“dafei1288”);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
connection = getConnection();
String sql = “insert into sink_ch_test(id,name,description) values (?,?,?)”;
pstmt = connection.prepareStatement(sql);
}
// 每条记录插入时调用一次
public void invoke(String value, Context context) throws Exception {
//{“database”:“test”,“data”:{“name”:“jacky”,“description”:“fffff”,“id”:8},“type”:“insert”,“table”:“test_cdc”}
Gson t = new Gson();
HashMap<String,Object> hs = t.fromJson(value,HashMap.class);
String database = (String)hs.get(“database”);
String table = (String)hs.get(“table”);
String type = (String)hs.get(“type”);
if(“test”.equals(database) && “test_cdc”.equals(table)){
自我介绍一下,小编13年上海交大结业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里不绝到如今。
深知大多数Java工程师,想要提升技能,往往是自己探索成长大概是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易遇到天花板技术故步自封!
因此收集整理了一份《2024年Java开发全套学习资料》,初志也很简朴,就是希望能够资助到想自学提升又不知道该从何学起的朋侪,同时减轻各人的负担。https://img-blog.csdnimg.cn/img_convert/9ae68ff911f466b45fd467e04f371396.jpeg
https://img-blog.csdnimg.cn/img_convert/ba11c6874f705b2c5608d3f33a53a739.png
https://img-blog.csdnimg.cn/img_convert/ca476b2f4d61079918e16e5493e5a0fc.png
既有适合小白学习的零基础资料,也有适合3年以上履历的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包罗大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有资助,可以扫码获取!!(备注Java获取)
https://img-blog.csdnimg.cn/img_convert/95f8d7eb671e8c4ddf101c3bcf8a8fc7.jpeg 分享

首先分享一份学习大纲,内容较多,涵盖了互联网行业全部的盛行以及焦点技术,以截图情势分享:
(亿级流量性能调优实战+一线大厂分布式实战+架构师筑基必备技能+筹划思想开源框架解读+性能直线提升架构技术+高效存储让项目性能腾飞+分布式扩展到微服务架构…实在是太多了)
其次分享一些技术知识,以截图情势分享一部分:
Tomcat架构剖析:
https://img-blog.csdnimg.cn/img_convert/aa04675870c342b5bc2baf280fff25c2.webp?x-oss-process=image/format,png
算法训练+高分宝典:
https://img-blog.csdnimg.cn/img_convert/e10470037ce529bce5a4f721b68a98ac.webp?x-oss-process=image/format,png
Spring Cloud+Docker微服务实战:
https://img-blog.csdnimg.cn/img_convert/ce7a42482e1cac42e9f2f53323582a49.webp?x-oss-process=image/format,png
末了分享一波面试资料:
   切莫死记硬背,小心面试官直接让你出门右拐
1000道互联网Java面试题:
https://img-blog.csdnimg.cn/img_convert/391465bed223e269704b74110b0d6aa4.webp?x-oss-process=image/format,png
Java高级架构面试知识整理:
https://img-blog.csdnimg.cn/img_convert/9229861052a740f5152caa78049e71a3.webp?x-oss-process=image/format,png
《互联网大厂面试真题剖析、进阶开发焦点学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
yle=“zoom: 33%;” />
分享

首先分享一份学习大纲,内容较多,涵盖了互联网行业全部的盛行以及焦点技术,以截图情势分享:
(亿级流量性能调优实战+一线大厂分布式实战+架构师筑基必备技能+筹划思想开源框架解读+性能直线提升架构技术+高效存储让项目性能腾飞+分布式扩展到微服务架构…实在是太多了)
其次分享一些技术知识,以截图情势分享一部分:
Tomcat架构剖析:
[外链图片转存中…(img-UyrrRNda-1712857483891)]
算法训练+高分宝典:
[外链图片转存中…(img-UQAMcEc5-1712857483891)]
Spring Cloud+Docker微服务实战:
[外链图片转存中…(img-HPRzuChK-1712857483891)]
末了分享一波面试资料:
   切莫死记硬背,小心面试官直接让你出门右拐
1000道互联网Java面试题:
[外链图片转存中…(img-nyhELWtO-1712857483891)]
Java高级架构面试知识整理:
[外链图片转存中…(img-oiRoZ9kg-1712857483891)]
《互联网大厂面试真题剖析、进阶开发焦点学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 非常钟掌握 Flink CDC,实现Mysql数据增量备份到Clickhouse [纯干货,发起