日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

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

發(fā)布時(shí)間:2024/8/23 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Canal Mysql同步至ES/Hbase只有新增时生效,修改删除不生效 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

問(wèn)題描述

新增Mysql數(shù)據(jù)時(shí),ES、Hbase數(shù)據(jù)會(huì)同步成功;當(dāng)刪除Mysql數(shù)據(jù),或者修改Mysql數(shù)據(jù)時(shí)同步ES、Hbase數(shù)據(jù)無(wú)變化(PS:修改和刪除加上LIMIT xxx 就可以成功。)

問(wèn)題分析

通過(guò)查看日志發(fā)現(xiàn)新增和刪除記錄的日志區(qū)別:新增data有數(shù)據(jù),修改、刪除 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"}

通過(guò)查看源碼我們發(fā)現(xiàn),當(dāng)data為null時(shí),直接return,不進(jìn)行下一步操作

/*** 更新操作dml** @param config es配置* @param dml dml數(shù)據(jù)*/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;}....

問(wèn)題找到,原因就是我們沒(méi)有記錄修改的數(shù)據(jù)。
再次查看源碼,找一下是從什么時(shí)候data沒(méi)有的。
發(fā)現(xiàn)在MessageUtil中有數(shù)據(jù)轉(zhuǎn)換,加入日志,重新打包將 connector.core-1.1.5.jar 替換掉,重啟服務(wù),我們查看下從數(shù)據(jù)接收進(jìn)來(lái)是不是就已經(jīng)沒(méi)有了

/*** Message對(duì)象解析工具類** @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 替換掉,重啟服務(wù),我們查看下從數(shù)據(jù)接收進(jìn)來(lái)是不是就已經(jīng)沒(méi)有了logger.info("row:{}",rowChange.getRowDatasList());....

重啟后在adapter日志中發(fā)現(xiàn),在接收數(shù)據(jù)時(shí)已經(jīng)沒(méi)有了。

隨后我們從 Mysql方面分析,根據(jù)Mysql Binlog三種格式我們知道,當(dāng)類型設(shè)置Statement或者M(jìn)ixed時(shí)會(huì)導(dǎo)致數(shù)據(jù)記錄不是全部列。

這里簡(jiǎn)單介紹下三種區(qū)別

MySQL 5.5 中對(duì)于二進(jìn)制日志 (binlog) 有 3 種不同的格式可選:Mixed,Statement,Row,默認(rèn)格式是 Statement。總結(jié)一下這三種格式日志的優(yōu)缺點(diǎn)。MySQL Replication 復(fù)制可以是基于一條語(yǔ)句 (Statement Level) ,也可以是基于一條記錄 (Row Level),可以在 MySQL 的配置參數(shù)中設(shè)定這個(gè)復(fù)制級(jí)別,不同復(fù)制級(jí)別的設(shè)置會(huì)影響到 Master 端的 bin-log 日志格式。1. Row 日志中會(huì)記錄成每一行數(shù)據(jù)被修改的形式,然后在 slave 端再對(duì)相同的數(shù)據(jù)進(jìn)行修改。優(yōu)點(diǎn):在 row 模式下,bin-log 中可以不記錄執(zhí)行的 SQL 語(yǔ)句的上下文相關(guān)的信息,僅僅只需要記錄那一條記錄被修改了,修改成什么樣了。所以 row 的日志內(nèi)容會(huì)非常清楚的記錄下每一行數(shù)據(jù)修改的細(xì)節(jié),非常容易理解。而且不會(huì)出現(xiàn)某些特定情況下的存儲(chǔ)過(guò)程或 function ,以及 trigger 的調(diào)用和觸發(fā)無(wú)法被正確復(fù)制的問(wèn)題。缺點(diǎn):在 row 模式下,所有的執(zhí)行的語(yǔ)句當(dāng)記錄到日志中的時(shí)候,都將以每行記錄的修改來(lái)記錄,這樣可能會(huì)產(chǎn)生大量的日志內(nèi)容,比如有這樣一條 update 語(yǔ)句:UPDATE product SET owner_member_id = 'b' WHERE owner_member_id = 'a' 執(zhí)行之后,日志中記錄的不是這條 update 語(yǔ)句所對(duì)應(yīng)的事件 (MySQL 以事件的形式來(lái)記錄 bin-log 日志) ,而是這條語(yǔ)句所更新的每一條記錄的變化情況,這樣就記錄成很多條記錄被更新的很多個(gè)事件。自然,bin-log 日志的量就會(huì)很大。尤其是當(dāng)執(zhí)行 alter table 之類的語(yǔ)句的時(shí)候,產(chǎn)生的日志量是驚人的。因?yàn)?MySQL 對(duì)于 alter table 之類的表結(jié)構(gòu)變更語(yǔ)句的處理方式是整個(gè)表的每一條記錄都需要變動(dòng),實(shí)際上就是重建了整個(gè)表。那么該表的每一條記錄都會(huì)被記錄到日志中。2. Statement 每一條會(huì)修改數(shù)據(jù)的 SQL 都會(huì)記錄到 master 的 bin-log 中。slave 在復(fù)制的時(shí)候 SQL 進(jìn)程會(huì)解析成和原來(lái) master 端執(zhí)行過(guò)的相同的 SQL 再次執(zhí)行。優(yōu)點(diǎn):在 statement 模式下,首先就是解決了 row 模式的缺點(diǎn),不需要記錄每一行數(shù)據(jù)的變化,減少了 bin-log 日志量,節(jié)省 I/O 以及存儲(chǔ)資源,提高性能。因?yàn)樗恍枰涗浽?master 上所執(zhí)行的語(yǔ)句的細(xì)節(jié),以及執(zhí)行語(yǔ)句時(shí)候的上下文的信息。缺點(diǎn):在 statement 模式下,由于他是記錄的執(zhí)行語(yǔ)句,所以,為了讓這些語(yǔ)句在 slave 端也能正確執(zhí)行,那么他還必須記錄每條語(yǔ)句在執(zhí)行的時(shí)候的一些相關(guān)信息,也就是上下文信息,以保證所有語(yǔ)句在 slave 端杯執(zhí)行的時(shí)候能夠得到和在 master 端執(zhí)行時(shí)候相同的結(jié)果。另外就是,由于 MySQL 現(xiàn)在發(fā)展比較快,很多的新功能不斷的加入,使 MySQL 的復(fù)制遇到了不小的挑戰(zhàn),自然復(fù)制的時(shí)候涉及到越復(fù)雜的內(nèi)容,bug 也就越容易出現(xiàn)。在 statement 中,目前已經(jīng)發(fā)現(xiàn)的就有不少情況會(huì)造成 MySQL 的復(fù)制出現(xiàn)問(wèn)題,主要是修改數(shù)據(jù)的時(shí)候使用了某些特定的函數(shù)或者功能的時(shí)候會(huì)出現(xiàn),比如:sleep() 函數(shù)在有些版本中就不能被正確復(fù)制,在存儲(chǔ)過(guò)程中使用了 last_insert_id() 函數(shù),可能會(huì)使 slave 和 master 上得到不一致的 id 等等。由于 row 是基于每一行來(lái)記錄的變化,所以不會(huì)出現(xiàn)類似的問(wèn)題。3. Mixed 從官方文檔中看到,之前的 MySQL 一直都只有基于 statement 的復(fù)制模式,直到 5.1.5 版本的 MySQL 才開(kāi)始支持 row 復(fù)制。從 5.0 開(kāi)始,MySQL 的復(fù)制已經(jīng)解決了大量老版本中出現(xiàn)的無(wú)法正確復(fù)制的問(wèn)題。但是由于存儲(chǔ)過(guò)程的出現(xiàn),給 MySQL Replication 又帶來(lái)了更大的新挑戰(zhàn)。另外,看到官方文檔說(shuō),從 5.1.8 版本開(kāi)始,MySQL 提供了除 Statement 和 Row 之外的第三種復(fù)制模式:Mixed,實(shí)際上就是前兩種模式的結(jié)合。在 Mixed 模式下,MySQL 會(huì)根據(jù)執(zhí)行的每一條具體的 SQL 語(yǔ)句來(lái)區(qū)分對(duì)待記錄的日志形式,也就是在 statement 和 row 之間選擇一種。新版本中的 statment 還是和以前一樣,僅僅記錄執(zhí)行的語(yǔ)句。而新版本的 MySQL 中對(duì) row 模式也被做了優(yōu)化,并不是所有的修改都會(huì)以 row 模式來(lái)記錄,比如遇到表結(jié)構(gòu)變更的時(shí)候就會(huì)以 statement 模式來(lái)記錄,如果 SQL 語(yǔ)句確實(shí)就是 update 或者 delete 等修改數(shù)據(jù)的語(yǔ)句,那么還是會(huì)記錄所有行的變更。

最后去查看我們配置文件,發(fā)現(xiàn)我們的配置文件設(shè)置了兩個(gè) binlog_format (復(fù)制之前的配置文件,在上面加了一個(gè) binlog_format=ROW,但是未生效,被下面的覆蓋了。。。。。)

最終刪除

log_bin = mysql-bin binlog_format = mixed

保留

log_bin=mysql-bin # 開(kāi)啟 binlog binlog_format=ROW # 選擇 ROW 模式 binlog_row_image=FULL

重啟Mysql、canal 再次執(zhí)行修改刪除,data中已經(jīng)有記錄

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"}

文章開(kāi)頭有說(shuō):PS:修改和刪除加上LIMIT xxx 就可以成功。原因就是ROW和mixed的區(qū)別。

其他類似問(wèn)題

當(dāng)為mixed時(shí),在Navicat直接點(diǎn)+新增數(shù)據(jù)時(shí)data也同樣為空。改為ROW即可

總結(jié)

以上是生活随笔為你收集整理的Canal Mysql同步至ES/Hbase只有新增时生效,修改删除不生效的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。