Canal Mysql同步至ES/Hbase只有新增时生效,修改删除不生效

问题描述

新增Mysql数据时,ES、Hbase数据会同步成功;当删除Mysql数据,或者修改Mysql数据时同步ES、Hbase数据无变化(PS:修改和删除加上LIMIT xxx 就可以成功。)

问题分析

通过查看日志发现新增和删除记录的日志区别:新增data有数据,修改、删除 data为空

2021-09-22 10:29:03.551 [pool-1-thread-1] DEBUG c.a.o.c.client.adapter.hbase.service.HbaseSyncService - DML: {"data":[{"id":"d9a63f30-1b4c-11ec-99c4-708cb6f5eaa6","name":"aaabbbcccc","age":null,"age_2":null,"message":null,"insert_time":null}],"database":"test2","destination":"example","es":1632277742000,"groupId":"g1","isDdl":false,"old":null,"pkNames":["id"],"sql":"","table":"testsync","ts":1632277743140,"type":"INSERT"}
2021-09-22 10:19:36.703 [pool-1-thread-1] DEBUG c.a.o.c.client.adapter.hbase.service.HbaseSyncService - DML: {"data":null,"database":"test2","destination":"example","es":1632277176000,"groupId":"g1","isDdl":false,"old":null,"pkNames":[],"sql":"DELETE FROM testsync where name = 'aaabbbcccc'","table":"testsync","ts":1632277176566,"type":"DELETE"}
2021-09-22 10:19:36.704 [pool-1-thread-1] DEBUG c.a.o.canal.client.adapter.es.core.service.ESSyncService - DML: {"data":null,"database":"test2","destination":"example","es":1632277176000,"groupId":"g1","isDdl":false,"old":null,"pkNames":[],"sql":"DELETE FROM testsync where name = 'aaabbbcccc'","table":"testsync","ts":1632277176566,"type":"DELETE"} 

通过查看源码我们发现,当data为null时,直接return,不进行下一步操作

/*** 更新操作dml** @param config es配置* @param dml dml数据*/private void update(ESSyncConfig config, Dml dml) {List<Map<String, Object>> dataList = dml.getData();List<Map<String, Object>> oldList = dml.getOld();if (dataList == null || dataList.isEmpty() || oldList == null || oldList.isEmpty()) {return;}....

问题找到,原因就是我们没有记录修改的数据。
再次查看源码,找一下是从什么时候data没有的。
发现在MessageUtil中有数据转换,加入日志,重新打包将 connector.core-1.1.5.jar 替换掉,重启服务,我们查看下从数据接收进来是不是就已经没有了

/*** Message对象解析工具类** @author rewerma 2018-8-19 下午06:14:23* @version 1.0.0*/
public class MessageUtil {private static final Logger logger = LoggerFactory.getLogger(MessageUtil.class);public static List<CommonMessage> convert(Message message) {if (message == null) {return null;}List<CanalEntry.Entry> entries = message.getEntries();List<CommonMessage> msgs = new ArrayList<>(entries.size());for (CanalEntry.Entry entry : entries) {if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN|| entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {continue;}CanalEntry.RowChange rowChange;try {rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue());} catch (Exception e) {throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),e);}// 加入日志,重新打包将 connector.core-1.1.5.jar 替换掉,重启服务,我们查看下从数据接收进来是不是就已经没有了logger.info("row:{}",rowChange.getRowDatasList());....

重启后在adapter日志中发现,在接收数据时已经没有了。

随后我们从 Mysql方面分析,根据Mysql Binlog三种格式我们知道,当类型设置Statement或者Mixed时会导致数据记录不是全部列。

这里简单介绍下三种区别

MySQL 5.5 中对于二进制日志 (binlog) 有 3 种不同的格式可选:Mixed,Statement,Row,默认格式是 Statement。总结一下这三种格式日志的优缺点。MySQL Replication 复制可以是基于一条语句 (Statement Level) ,也可以是基于一条记录 (Row Level),可以在 MySQL 的配置参数中设定这个复制级别,不同复制级别的设置会影响到 Master 端的 bin-log 日志格式。1. Row
日志中会记录成每一行数据被修改的形式,然后在 slave 端再对相同的数据进行修改。优点:在 row 模式下,bin-log 中可以不记录执行的 SQL 语句的上下文相关的信息,仅仅只需要记录那一条记录被修改了,修改成什么样了。所以 row 的日志内容会非常清楚的记录下每一行数据修改的细节,非常容易理解。而且不会出现某些特定情况下的存储过程或 function ,以及 trigger 的调用和触发无法被正确复制的问题。缺点:在 row 模式下,所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比如有这样一条 update 语句:UPDATE product SET owner_member_id = 'b' WHERE owner_member_id = 'a'
执行之后,日志中记录的不是这条 update 语句所对应的事件 (MySQL 以事件的形式来记录 bin-log 日志) ,而是这条语句所更新的每一条记录的变化情况,这样就记录成很多条记录被更新的很多个事件。自然,bin-log 日志的量就会很大。尤其是当执行 alter table 之类的语句的时候,产生的日志量是惊人的。因为 MySQL 对于 alter table 之类的表结构变更语句的处理方式是整个表的每一条记录都需要变动,实际上就是重建了整个表。那么该表的每一条记录都会被记录到日志中。2. Statement
每一条会修改数据的 SQL 都会记录到 master 的 bin-log 中。slave 在复制的时候 SQL 进程会解析成和原来 master 端执行过的相同的 SQL 再次执行。优点:在 statement 模式下,首先就是解决了 row 模式的缺点,不需要记录每一行数据的变化,减少了 bin-log 日志量,节省 I/O 以及存储资源,提高性能。因为他只需要记录在 master 上所执行的语句的细节,以及执行语句时候的上下文的信息。缺点:在 statement 模式下,由于他是记录的执行语句,所以,为了让这些语句在 slave 端也能正确执行,那么他还必须记录每条语句在执行的时候的一些相关信息,也就是上下文信息,以保证所有语句在 slave 端杯执行的时候能够得到和在 master 端执行时候相同的结果。另外就是,由于 MySQL 现在发展比较快,很多的新功能不断的加入,使 MySQL 的复制遇到了不小的挑战,自然复制的时候涉及到越复杂的内容,bug 也就越容易出现。在 statement 中,目前已经发现的就有不少情况会造成 MySQL 的复制出现问题,主要是修改数据的时候使用了某些特定的函数或者功能的时候会出现,比如:sleep() 函数在有些版本中就不能被正确复制,在存储过程中使用了 last_insert_id() 函数,可能会使 slave 和 master 上得到不一致的 id 等等。由于 row 是基于每一行来记录的变化,所以不会出现类似的问题。3. Mixed
从官方文档中看到,之前的 MySQL 一直都只有基于 statement 的复制模式,直到 5.1.5 版本的 MySQL 才开始支持 row 复制。从 5.0 开始,MySQL 的复制已经解决了大量老版本中出现的无法正确复制的问题。但是由于存储过程的出现,给 MySQL Replication 又带来了更大的新挑战。另外,看到官方文档说,从 5.1.8 版本开始,MySQL 提供了除 Statement 和 Row 之外的第三种复制模式:Mixed,实际上就是前两种模式的结合。在 Mixed 模式下,MySQL 会根据执行的每一条具体的 SQL 语句来区分对待记录的日志形式,也就是在 statement 和 row 之间选择一种。新版本中的 statment 还是和以前一样,仅仅记录执行的语句。而新版本的 MySQL 中对 row 模式也被做了优化,并不是所有的修改都会以 row 模式来记录,比如遇到表结构变更的时候就会以 statement 模式来记录,如果 SQL 语句确实就是 update 或者 delete 等修改数据的语句,那么还是会记录所有行的变更。

最后去查看我们配置文件,发现我们的配置文件设置了两个 binlog_format (复制之前的配置文件,在上面加了一个 binlog_format=ROW,但是未生效,被下面的覆盖了。。。。。)

最终删除

log_bin = mysql-bin 
binlog_format = mixed 

保留

log_bin=mysql-bin # 开启 binlog
binlog_format=ROW # 选择 ROW 模式
binlog_row_image=FULL

重启Mysql、canal 再次执行修改删除,data中已经有记录

2021-09-22 11:20:45.456 [pool-1-thread-1] DEBUG c.a.o.c.client.adapter.hbase.service.HbaseSyncService - DML: {"data":[{"id":"10d7e4b8-1b54-11ec-8673-708cb6f5eaa6","name":"bbb","age":null,"age_2":null,"message":null,"insert_time":1632280844000}],"database":"test2","destination":"example","es":1632280844000,"groupId":"g1","isDdl":false,"old":[{"name":"aaabbbcccc","insert_time":null}],"pkNames":["id"],"sql":"","table":"testsync","ts":1632280845389,"type":"UPDATE"}
2021-09-22 11:20:45.517 [pool-1-thread-1] DEBUG c.a.o.canal.client.adapter.es.core.service.ESSyncService - DML: {"data":[{"id":"10d7e4b8-1b54-11ec-8673-708cb6f5eaa6","name":"bbb","age":null,"age_2":null,"message":null,"insert_time":1632280844000}],"database":"test2","destination":"example","es":1632280844000,"groupId":"g1","isDdl":false,"old":[{"name":"aaabbbcccc","insert_time":null}],"pkNames":["id"],"sql":"","table":"testsync","ts":1632280845389,"type":"UPDATE"} 

文章开头有说:PS:修改和删除加上LIMIT xxx 就可以成功。原因就是ROW和mixed的区别。

其他类似问题

在这里插入图片描述

当为mixed时,在Navicat直接点+新增数据时data也同样为空。改为ROW即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/509631.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 11 中的右值引用

C 11 中的右值引用 右值引用的功能 首先&#xff0c;我并不介绍什么是右值引用&#xff0c;而是以一个例子里来介绍一下右值引用的功能&#xff1a; #include <iostream> #include <vector> using namespace std; class obj { public : …

LinkedHashSet类

List接口: 允许元素重复,记录先后添加顺序. Set接口: 不允许元素重复,不记录先后添加顺序. 需求: 不允许元素重复,但是需要保证先后添加的顺序. LinkedHashSet:底层才有哈希表和链表算法. 哈希表:来保证唯一性,.此时就是HashSet,在哈希表中元素没有先后顺序. 链表: 来记录…

数据结构实验之串一:KMP简单应用

题目描述 给定两个字符串string1和string2&#xff0c;判断string2是否为string1的子串。输入 输入包含多组数据&#xff0c;每组测试数据包含两行&#xff0c;第一行代表string1(长度小于1000000)&#xff0c;第二行代表string2&#xff08;长度小于1000000&#xff09;&#…

Canal Mysql binlog 同步至 ElasticSearch 详细介绍

文章目录数据同步ElasticSearch单表基本配置适配器映射文件详细介绍&#xff08;单表、多表映射介绍&#xff09;单表映射索引示例sql单表映射索引示例sql带函数或运算操作多表映射(一对一, 多对一)索引示例sql多表映射(一对多)索引示例sql其它类型的sql示例注意事项本文详细介…

基于C++11的线程池

背景 在传统的收到任务即创建线程的情况下&#xff0c;我们每收到一个任务&#xff0c;就创建一个线程&#xff0c;执行任务&#xff0c;销毁线程&#xff0c; 我们把这三个过程所用的时间分别记做T1,T2,T3 任务本身所用的时间仅占T2/(T1T2T3),这在任务本身所用时间很短的情况下…

集合的工具类

集合操作的工具类: 1):Arrays类: 2):Collections类. Arrays类: 在Collection接口中有一个方法叫toArray把集合转换为Object数组. 把集合转换为数组: Object[] arr 集合对象.toArray(); 数组也可以转换为集合(List集合): public static List asList(T… a) 等价于public …

Docker入门到精通开发指南(一文搞懂)

文章目录安装官方安装文档具体安装步骤1.卸载之前的版本(如果之前未用过忽略该步骤)2.安装相关依赖3.设置docker镜像4.安装docker安装latest版本指定版本安装5.启动docker6.查看docker版本7.运行一个docker hello world8.卸载docker9.配置阿里云镜像加速地址docker常用命令dock…

数据结构实验之串二:字符串匹配

题目描述 给定两个字符串string1和string2&#xff0c;判断string2是否为string1的子串。 输入 输入包含多组数据&#xff0c;每组测试数据包含两行&#xff0c;第一行代表string1&#xff0c;第二行代表string2&#xff0c;string1和string2中保证不出现空格。(string1和strin…

Unicode和Utf-8

很久很久以前&#xff0c;有一群人&#xff0c;他们决定用8个可以开合的晶体管来组合成不同的状态&#xff0c;以表示世界上的万物。他们看到8个开关状态是好的&#xff0c;于是他们把这称为”字节“。再后来&#xff0c;他们又做了一些可以处理这些字节的机器&#xff0c;机器…

如何向Maven中央仓库提交自己的Jar包(发布自己的Jar包到中央仓库)

文章目录注册账号GPG 安装安装生成密钥上传公钥Maven配置上传到Maven仓库修改项目的配置&#xff0c;填写基本信息执行编译命令登录网站配置发布项目中应用遇到的问题解决方法本文将介绍如何将自己的jar包发布至公共的中央仓库&#xff0c;通过maven方式进行引用 注册账号 注册…

数据结构实验之串三:KMP应用

题目描述 有n个小朋友&#xff0c;每个小朋友手里有一些糖块&#xff0c;现在这些小朋友排成一排&#xff0c;编号是由1到n。现在给出m个数&#xff0c;能不能唯一的确定一对值l和r(l < r)&#xff0c;使得这m个数刚好是第l个小朋友到第r个小朋友手里的糖块数&#xff1f;输…

C++读写锁

读写锁实际是一种特殊的自旋锁&#xff0c;它把对共享资源的访问者划分成读者和写者&#xff0c;读者只对共享资源进行读访问&#xff0c;写者则需要对共享资源进行写操作。 读写锁实际是一种特殊的自旋锁&#xff0c;它把对共享资源的访问者划分成读者和写者&#xff0c;读者只…

List和Set以及Map的选用

选用哪一种容器取决于每一种容器的存储特点以及当前业务的需求: List: 单一元素集合. 允许元素重复/记录元素的添加顺序. Set:单一元素集合. 不允许元素重复/不记录元素的添加顺序. 既要不重复,又要保证先后顺序:LinkedHashSet. Map: 双元素集合. 如果存储数据的时候,还得…

FastDFS文件服务器安装

文章目录环境准备使用的系统软件磁盘目录安装libfastcommon安装FastDFS安装fastdfs-nginx-module安装nginx单机部署tracker配置storage配置client测试配置nginx访问分布式部署tracker配置storage配置client测试配置nginx访问启动防火墙trackerstoragenginx检测集群说明配置文件…

学密码学一定得学程序

题目描述 曾经&#xff0c;ZYJ同学非常喜欢密码学。有一天&#xff0c;他发现了一个很长很长的字符串S1。他很好奇那代表着什么&#xff0c;于是神奇的WL给了他另一个字符串S2。但是很不幸的是&#xff0c;WL忘记跟他说是什么意思了。这个时候&#xff0c;ZYJ不得不求助与伟大的…

boost::shared_mutex

前一篇介绍的条件变量可以进行进程间通信&#xff0c;用来实现生产者/消费者模型。今天介绍的共享互斥量用来实现缓冲区读写模型&#xff0c;与生产者/消费者模型不同的地方是&#xff0c;消费者消费产品后&#xff0c;被消费的产品就不存在了&#xff0c;所以消费者线程也要互…

Map集合类

映射的数学解释: 设A、B是两个非空集合&#xff0c;如果存在一个法则f&#xff0c;使得对A中的每个元素a&#xff0c;按法则f&#xff0c;在B中有唯一确定的元素b与之对应&#xff0c;则称f为从A到B的映射&#xff0c;记作f&#xff1a;A→B。 映射关系(两个集合):A集合和B集…

github 国内加速镜像

GitHub 镜像访问 这里提供两个最常用的镜像地址&#xff08;别登录账号&#xff09;&#xff1a; https://github.com.cnpmjs.org https://hub.fastgit.org 也就是说上面的镜像就是一个克隆版的Github&#xff0c;你可以访问上面的镜像网站&#xff0c;网站的内容跟Github是完…

数据结构实验之二叉树二:遍历二叉树

题目描述 已知二叉树的一个按先序遍历输入的字符序列&#xff0c;如abc,,de,g,,f,,, (其中,表示空结点)。请建立二叉树并按中序和后序的方式遍历该二叉树。 输入 连续输入多组数据&#xff0c;每组数据输入一个长度小于50个字符的字符串。 输出 每组输入数据对应输出2行&#x…