嘿嘿 又知道多一点点 说来有些惭愧 现在才写 各方面因素造成的延迟
实时监控mysql表除了canal还有什么,还有很多,比如
mysql-binlog-connector-java
GitHub - liufeiit/mysql-binlog-connector-java: mysql-binlog-connector-java
java库,基于复制协议解析读取mysql二进制日志(实时订阅/消费)
自然canal还有这个client还有下面要提到都是需要开启binlog的show variables like 'log_bin';
log_bin=mysql-bin
binlog-format=ROW#格式 statement row mixed
server-id=1#sql从哪个server写入
<dependency>
<groupId>com.github.shyiko</groupId>
<artifactId>mysql-binlog-connector-java</artifactId>
<version>0.2.2</version>
</dependency>
binlog
row:仅保存被修改的细节,每一行数据的变化:前/后数据,被修改行的实际数据,不记录上下文
statement:记录每条会修改数据的sql语句和执行结果,执行语句 上下文环境,函数会有问题
mixed:混合简单的statement 复杂row,对于insert update delete的binlog事件类型=query事件
事件
query与数据库关,begin / drop table / truncate table
table_map:记录下一个操作对应的表信息
xid:标记事务提交
原理
- 创建BinaryLogClient,设置主机 port user password等必要参数
- 客户端连接mysql,发送dump请求,开始从指定位置发送日志事件,可指定日志的起始和结束位置,及需要订阅的事件类型、数据库名称或表名称等过滤条件
- BinaryLogClient接收到事件,解析转换为Java对象,尝试回调一个或多个事件监听器。每个监听器可以实现自己的逻辑,如将事件记录到文件、将事件写入队列或执行自定义代码等
- 应用程序可随时关闭客户端连接,MySQL将停止向客户端发送事件,并且客户端将在退出之前自动处理所有未处理的事件
write_rows插入数据 update_rows delete_rows 具体看代码,很清晰 但是也有点小问题 评论区指出吧大佬们!
这个执行起来很简单,主要的代码在下面了
建议宝贝直接debug看看参数,进方法里面看看源码 yyds
public static void main(String[] args) throws IOException {
/**
* BinaryLogClient 类是 MySQL 提供的一个底层使用了 MySQL 原生协议和通信机制的 Java 客户端,用于监听 MySQL 数据库的二进制日志(Binary Log),并实现实时的数据同步
*/
BinaryLogClient client = new BinaryLogClient("IP", 3306, "账号", "密码");
/**
* EventDeserializer 是一个接口,将 Event 数据从序列化格式反序列化为对象
*/
EventDeserializer eventDeserializer = new EventDeserializer();
eventDeserializer.setCompatibilityMode(
// 时间戳表示 自 Unix 纪元(1970 年 1 月 1 日 UTC)以来的毫秒数
EventDeserializer.CompatibilityMode.DATE_AND_TIME_AS_LONG,
//通过使用字节数组来表示字符和二进制数据,保留其编码和格式信息
EventDeserializer
.CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY
);
client.setEventDeserializer(eventDeserializer);
//serverId是一个客户端与MySQL实例之间的唯一标识符
//有多个客户端同时订阅同一个MySQL实例上的二进制日志,那么每个客户端的serverId应该是唯一的
client.setServerId(serverId);
//设置需要读取的Binlog的文件以及位置,否则,client会从"头"开始读取Binlog并监听
//client.setBinlogFilename("mysql-bin.000001");
//client.setBinlogPosition("/data/");
Thread thread = new Thread(() -> {
client.registerEventListener(event -> {
final EventData data = event.getData();
if (data instanceof WriteRowsEventData) {
WriteRowsEventData writeRowsEventData = (WriteRowsEventData) data;
} else if (data instanceof UpdateRowsEventData) {
UpdateRowsEventData updateRowsEventData = (UpdateRowsEventData) data;
} else if (data instanceof DeleteRowsEventData) {
DeleteRowsEventData deleteRowsEventData = (DeleteRowsEventData) data;
} else if (data instanceof QueryEventData) {
QueryEventData queryEventData = (QueryEventData) data;
String database = queryEventData.getDatabase();
if ("jeecg-boot".equals(database)) {
//这个地方要dubug具体看一下如何取值
String sql = queryEventData.getSql();
if (sql != null && sql.length() >= 10) {
String[] s = sql.split(" ");
String type = s[0];
String tableName = null;
type = type.toUpperCase();
switch (type) {
case "INSERT":
break;
case "DELETE":
break;
case "UPDATE":
tableName = s[1];
break;
default:
break;
}
if (tableName != null) {
tableName = tableName.replaceAll("`", "").replaceAll("'", "").replaceAll("\\.", "").toLowerCase();
if (TABLE_NAME.contains(tableName)) {
}
}
}
}
}
});
client.registerLifecycleListener(new BinaryLogClient.LifecycleListener() {
@Override
public void onConnect(BinaryLogClient client) {
logger.info("Connected to MySQL server");
}
@Override
public void onCommunicationFailure(BinaryLogClient client, Exception ex) {
logger.error("Communication failure with MySQL server", ex);
}
@Override
public void onEventDeserializationFailure(BinaryLogClient client, Exception ex) {
logger.error("Event deserialization failure", ex);
}
@Override
public void onDisconnect(BinaryLogClient client) {
logger.warn("Disconnected from MySQL server");
// 在这里添加重新连接或其他处理逻辑
}
});
try {
client.connect();
} catch (IOException e) {
//
}
});
return thread;
}
}
durid
这个引入依赖jar,配置文件替换驱动 基本操作就不说了
配置文件需要配置filters监控统计拦截filters:stat监控统计 log4j日志记录 wall防御sql注入
使用log4j记录日志,引入log4j的maven坐标
@Configuration
public class DruidConfig(){
@ConfigurationProperties(prefix="spring.datasource")
@Bean
public DataSource DruidDatasource(){
return new DruidDataSource();
}
@Bean
public ServletRegistrationBean servletRegistrationBean(){
//servlet配置,web.xml对servlet配置
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");
Map<String,String> hashMap = new HashMap<>();
hashMap.put("loginUsername","demo1");
hashMap.put("loginPassword","123");
hashMap.put("allow","");
bean.setInitParameters(hashMap);
return bean;
}
}
访问http://localhost:8080/druid
https://blog.51cto.com/u_12897/8658359
canal之前写了
debezium:增量的数据抽取及转换
分布式哦服务,依赖基于日志的CDC(Change Data Capture)变更数据捕捉 技术实现的组件!
支持全量、增量同步,同时支持 MySQL、PostgreSQL、Oracle 等数据库
CDC
主动查询:
上次更新的时间戳 版本号等信息
上次记录 对比
确定数据是否有变动,需要同步,实时性不高
事件接收:基于binlog 触发器trigger / 日志 transaction log/binary log/write-ahead log实现
当数据源变动 附加表上的触发器 binlog等途径 将操作记录下来
通过数据库底层协议 订阅消费 事件,重放数据库变动记录,实现同步,实时性高
主流数据源基本上都是支持的,mysql mongodb postgreSQL Oracle SQLServer Db2
捕获事务日志变更数据)
程序读取 流 获取 更改的事件
Kafka Connect
Kafka Connect 作为 Kafka broker之外的单独服务运行
Kafka 连接器是已打包好的 JAR ,只需下载这些文件到 Kafka Connect 指定的插件目录,做好配置,就可以直接用一条命令启动 Kafka Connect,支持分布式,通过心跳确认节点状态,自动协调,
Debezium连接器(上面的Debezium MySQL及Debezium PostgreSQL)属源连接器, Debezium 连接器部署到 Kafka Connect 中
MySQL 订阅 binlog;Postgres,订阅逻辑复制流,将这些更改传播到相应的Kafka主题中
默认情况下, 每个捕获的表都有一个主题
默认情况下,来自同一个数据库表的更改将写入名称与表名相对应的 Kafka 主题。如果需要,我们可以通过配置 Debezium 的主题路由转换来调整目标主题名称
快照:可选,拍摄数据库当前状态的初始快照。执行快照有不同的模式,支持增量快照,可以在连接器运行时触发
- 锁的方式:不同引擎 不同锁方式,mysql最小化锁表,读取表元data全局锁表避免minimal
- 局部快照,自定义快照语句加上where条件
- 增量快照,只读取部分 随时增加新表/触发快照,实时变更
- 信号表dbz_signal,特定格式 插入数据触发增量
过滤器:包含/排除列表过滤器 配置 捕获 的模式 表 列的集合,指定需要同步哪些表 列
屏蔽:来自特定列的值
监控:jmx进行监控
消息转换:消息路由 过滤 事件扁平化
数据处理
不同系统不同表现方式,decimal.handling.mode
- precise,精确读取,默认,如 JSON 把 DECIMAL变成Base64 编码的字符串;用Java 的 BigDecimal 类来精确存储数据,需在消费侧使用 BigDecimal 来读取这个原始值
- double,即转换成双精度浮点数,可能会损失精度,但是消费侧可直接使用
- string,即转换成字符串,在消费侧通常都可以用很简单的形式来把字符串转换回原格式
DATETIME存的是 BIGINT,及部分语言、数据库无UNSIGNED BIGINT格式溢出的问题
排错
权限问题;不同库 debezium不同权限要求
binlog失效/清除问题,导致连接器终止
集群节点配置错误,自动脚本配置
dbhistory主题配置错误,无数据库变更记录,消息无法通过数据结构检查,删除重启任务
Debezium Server
可配置的、即用型的应用程序,将更改事件从源数据库流式传输到各种消息传递基础设施之上
Embedded Engine
嵌入到我们的自定义 Java 应用程序中的库。在应用程序本身中使用更改事件(无需部署完整的Kafka和Kafka Connect集群)或将更改流式传输到 Amazon Kinesis 等替代消息传递代理有用
Flink CDC
GitHub - apache/flink-cdc: Flink CDC is a streaming data integration tool
2.X引入增量快照读取机制,全新的数据读取方式,并发读取 chunk粒度checkpoint
块chunk
exactly-once:checkpint精确一次性处理
无主键表处理:无主键表,利用额外字段识别数据记录唯一性
public static void main(String[] args) throws Exception {
//1.获取Flink执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
//通过FlinkCDC构建SourceFunction
DebeziumSourceFunction<String> sourceFunction = MySqlSource.<String>builder()
.hostname("hadoop102")
.port(3306)
.username("root")
.password("123456")
.databaseList("cdc_test") //监控的数据库
.tableList("cdc_test.user_info") //监控的数据库下的表
.deserializer(new StringDebeziumDeserializationSchema())//反序列化
.startupOptions(StartupOptions.initial())
.build();
DataStreamSource<String> dataStreamSource = env.addSource(sourceFunction);
//3.数据打印
dataStreamSource.print();
//4.启动任务
env.execute("FlinkCDC");
}
捕获*表中发生的变更,前后记录 flink cdc connector 直接在flink 以非约束模式stream使用
内置了bebezium引擎,抽取日志获取变更的能力,changelog转换为flink sql认识的rowData数据
https://blog.51cto.com/u_16175522/9046382