zoukankan      html  css  js  c++  java
  • Otter 同步出现时间列上值不一致问题

                                             Otter 同步出现时间列上值不一致问题

     

     

    背景:

    由于历史原因我们DB中引入了多源复制技术,在之后的使用过程中发现了一些弊端,于是准备去掉这套架构,使用otter来代替多源复制。在otter同步跑了很长一段时间之后,我们准备上线这套集群,却发现了一些不一致的情况。

     

    问题:

    之前otter使用的不是特别多,对其稳定性也不是很有信心,为了检验源库数据和目的数据的一致性,避免切换后出现数据不一致的问题,我们写脚本抽样比对了部分数据,结果发现两边的确存在数据不一致的情况,以下是其中一个案例。

    源数据

    < 2357 999999999 0 刘 2030420 罗 2409 红娘二部(易) 270 重庆解放碑店 2012218 陈 2020-05-18 02:27:04 2020-05-19 12:20:18 NULL 0 0 0 0 2020-05-19 12:20:18 2020-05-19 12:20:18

    目的数据

    > 2357 999999999 0 刘 2030420 罗 2409 红娘二部(易) 270 重庆解放碑店 2012218 陈 2020-05-18 02:27:04 2020-05-19 12:20:18 NULL 0 0 0 0 2020-05-19 12:20:18 2020-05-27 10:53:37

    表结构

    CREATE TABLE `ArchiveMeetDetail` (
    
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
    
      `memberId` int(11) NOT NULL ,
    
      `sex` tinyint(3) NOT NULL ,
    
      `trueName` varchar(10) NOT NULL ,
    
      `belongWorkerId` int(11) NOT NULL ,
    
      `belongWorkerName` varchar(20) NOT NULL ,
    
      `belongGroupId` int(11) NOT NULL ,
    
      `belongGroupName` varchar(20) NOT NULL ,
    
      `belongDeptId` int(11) NOT NULL ,
    
      `belongDeptName` varchar(20) NOT NULL ,
    
      `workerId` int(11) NOT NULL ,
    
      `workerName` varchar(255) NOT NULL ,
    
      `archiveTime` datetime NOT NULL ,
    
      `archivePassTime` datetime NOT NULL ,
    
      `firstMeetTime` datetime DEFAULT NULL ,
    
      `meetThisMonth` int(11) NOT NULL DEFAULT '0' ,
    
      `miniMeetThisMonth` int(11) NOT NULL DEFAULT '0' ,
    
      `meetTotal` int(11) NOT NULL DEFAULT '0' ,
    
      `miniMeetTotal` int(11) NOT NULL DEFAULT '0' ,
    
      `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ,
    
      `updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
    
      PRIMARY KEY (`id`),
    
      KEY `idx_member_id` (`memberId`) USING BTREE,
    
      KEY `idx_group_id` (`belongGroupId`) USING BTREE,
    
      KEY `idx_dept_id` (`belongDeptId`) USING BTREE,
    
      KEY `idx_archive_pass_time` (`archivePassTime`) USING BTREE
    
    ) ENGINE=InnoDB AUTO_INCREMENT=3543 DEFAULT CHARSET=utf8

    我们发现:

    1.都是这种updatetime时间列上的数据不一致。

    2.updatetime列上有ON UPDATE CURRENT_TIMESTAMP 子句,也就是每次更新的时候这列的值会自动更新为当前时间。

     

    排查:

    首先我们在源库解析binlog,提取对这个表修改的sql,主要是两个sql,一个update语句和一个insert语句。

    我们测试了update 语句在修改其他列或updatetime 列的情况,也测试了insert在指定updatetime值和不指定updatetime 值的情况(第一次可能测试的不是很仔细),结果都是源和目的的数据是完全一致的。

    之后,根据目的数据的修改时间(2020-05-27 10:53:37),我们排查目的库的binlog,找到修改这条记录所对应的sql。

    UPDATE `zhenai_crm_matchmaker`.`ArchiveMeetDetail` SET `firstMeetTime`=NULL, `updateTime`='2020-05-27 10:53:37', `miniMeetTotal`=0, `archiveTime`='2020-05-18 02:27:04', `belongDeptName`='重庆解放碑店', `workerId`=2012218, `createTime`='2020-05-19 12:20:18', `belongGroupId`=2409, `memberId`=999999999, `belongWorkerId`=2030420, `sex`=0, `belongGroupName`='红娘二部(易)', `trueName`='', `belongWorkerName`='', `meetTotal`=0, `workerName`='', `miniMeetThisMonth`=0, `belongDeptId`=270, `meetThisMonth`=0, `id`=2357, `archivePassTime`='2020-05-19 12:20:18' WHERE `firstMeetTime` IS NULL AND `updateTime`='2020-05-19 12:20:18' AND `miniMeetTotal`=0 AND `archiveTime`='2020-05-18 02:27:04' AND `belongDeptName`='重庆解放碑店' AND `workerId`=2030420 AND `createTime`='2020-05-19 12:20:18' AND `belongGroupId`=2409 AND `memberId`=999999999 AND `belongWorkerId`=2030420 AND `sex`=0 AND `belongGroupName`='红娘二部(易)' AND `trueName`='' AND `belongWorkerName`='' AND `meetTotal`=0 AND `workerName`='' AND `miniMeetThisMonth`=0 AND `belongDeptId`=270 AND `meetThisMonth`=0 AND `id`=2357 AND `archivePassTime`='2020-05-19 12:20:18' LIMIT 1; #start 142683935 end 142684421 time 2020-05-27 10:53:37

    如果目的库这个时间有修改,那么源库这个时间应该也是有同样的sql在执行,顺着这条思路,查查了源库binlog,解析出了对应的sql。

    UPDATE `zhenai_crm_matchmaker`.`ArchiveMeetDetail` SET `firstMeetTime`=NULL, `updateTime`='2020-05-19 12:20:18', `miniMeetTotal`=0, `archiveTime`='2020-05-18 02:27:04', `belongDeptName`='重庆解放碑店', `workerId`=2012218, `createTime`='2020-05-19 12:20:18', `belongGroupId`=2409, `memberId`=999999999, `belongWorkerId`=2030420, `sex`=0, `belongGroupName`='红娘二部(易)', `trueName`='', `belongWorkerName`='', `meetTotal`=0, `workerName`='', `miniMeetThisMonth`=0, `belongDeptId`=270, `meetThisMonth`=0, `id`=2357, `archivePassTime`='2020-05-19 12:20:18' WHERE `firstMeetTime` IS NULL AND `updateTime`='2020-05-19 12:20:18' AND `miniMeetTotal`=0 AND `archiveTime`='2020-05-18 02:27:04' AND `belongDeptName`='重庆解放碑店' AND `workerId`=2030420 AND `createTime`='2020-05-19 12:20:18' AND `belongGroupId`=2409 AND `memberId`=999999999 AND `belongWorkerId`=2030420 AND `sex`=0 AND `belongGroupName`='红娘二部(易)' AND `trueName`='' AND `belongWorkerName`='' AND `meetTotal`=0 AND `workerName`='' AND `miniMeetThisMonth`=0 AND `belongDeptId`=270 AND `meetThisMonth`=0 AND `id`=2357 AND `archivePassTime`='2020-05-19 12:20:18' LIMIT 1; #start 126420599 end 126421098 time 2020-05-27 10:53:37

    单看每一边的binlog及表的数据,都没有什么问题,binlog和数据都是对应的。但问题是同步过去为什么数据不一样,当然是因为执行的sql不一样。可是执行的sql为什么不一样呢?难道同步过去binlog不一样。但是这不可能的,主库和从库的binlog应该是一样的,

    那这里目的库的updatetime值为什么跟主库不一样呢?仔细看,就可以发现两点:

    1.源库在修改这条数据的时候也修改了updatetime 的值,但不是修改成最新的时间,而是跟原来一样的时间。

    2.而目的库,updatetime则是较新的一个值,很可能是当时执行时的时间。

    基于以上两点我们又做了测试,终于发现了问题。

     

     

    验证:

     

    测试SQL

    结果

    1

    update set updatetime = '2020-05-19 12:20:18' , workerName = 'test' ...

    两边数据不一致

    2

    update set updatetime = '2020-05-28 10:00:00' , workerName = 'test' ...

    两边数据一致

    我们发现出现不一致要有两个条件,

    第一,updatetime的值要修改成跟原来一样,也就是updatetime的值要保持不变,

    第二,除了updatetime列外,还需要变更其他列的数据。

    对于源库来说,它在执行update的时候把updatetime列的值修改成跟原来一样的值(如果不这么做,那么updatetime的值就会是执行时的时间)。而binlog传到目的端,在解析binog的时候,(由于一些参数)otter会根据列的变更来同步数据,而updatetime这列修改前的时间和修改后的时间是一样的,otter就没有同步这列,比如第一个sql,otter解析执行的sql可能是这个样子的:update set workerName = 'test' ... 。由于updatetime这列是自动更新的,所以实际是这样的:update set updatetime = '#current_time#' ,workerName = 'test' ... 。这就导致了目的时间是当前时间,和源库的时间不一样。

     

    解决:

    查询资料及官方文档,我们找到了otter中的一个可能造成这种结果的参数--channel 中的同步模式,有两种同步模式:
    行模式 ,兼容otter3的处理方案,改变记录中的任何一个字段,触发整行记录的数据同步,在目标库执行merge sql。

    列模式 ,基于log中的具体变更字段,按需同步。

    原先我们设置的是列模式,对于一般情况,同步不会有问题,但无法处理上面这种特殊情况下的同步。改为行模式后,经测试,两边的数据一致。

    转载请注明出处:http://www.cnblogs.com/ayard/
  • 相关阅读:
    sql2slack alash3al 开源的又个轻量级工具
    pgspider fetchq 扩展docker镜像
    godns 集成coredns 的demo
    godns 简单dnsmasq 的dns 替换方案
    aviary.sh 一个基于bash的分布式配置管理工具
    使用coredns 的template plugin实现一个xip 服务
    nginx 代理 coredns dns 服务
    基于nginx proxy dns server
    几个不错的geodns server
    spring boot rest api 最好添加servlet.context-path
  • 原文地址:https://www.cnblogs.com/ayard/p/14530571.html
Copyright © 2011-2022 走看看