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/
  • 相关阅读:
    【08】Python数据分析基础
    C#类和类成员初始化顺序
    C# 在子窗体调用父窗体的值(转)
    求实对称阵的 特征值 和 特征向量(转)
    Dev express 笔记
    Arcgis桌面开发,Python引用GDAL库的方法
    操作系统学习笔记--第三章--进程
    操作系统学习笔记--第一章--计算机系统概述
    GIS专业分析方法(待更新)
    C#中不用安装Oracle客户端连接Oracle数据库(转)
  • 原文地址:https://www.cnblogs.com/ayard/p/14530571.html
Copyright © 2011-2022 走看看