moiot / gravity

A Data Replication Center
Apache License 2.0
910 stars 173 forks source link

gravity全量同步时updated_at会发生改变 #289

Closed zhanjianS closed 4 years ago

zhanjianS commented 4 years ago

gravity mysql->tidb 全量+增量同步 时updated_at字段的数据会发生改变,变成当前时间 (测试的比当前时间小8小时 是因为这边k8s时区问题)

batch模式下也存在这个问题,用的最新的版本gravity0.9.71

表结构 图片

mysql的数据 图片

同步后tidb的数据 图片

模式配置 图片

Ryan-Git commented 4 years ago

这不是8小时啊,6-17 09:25 + 8 -> 6-17 17:25,比创建时间还早。。。

zhanjianS commented 4 years ago

不好意思 没描述清楚,mysql的数据是原始数据 是正确的数据,但是通过全量+增量的方式同步到tidb后,updated_at发生改变,变成当前时间的时间-8小时,按理说tidb的数据应该是myql端一致的

Ryan-Git commented 4 years ago

能截一个完整数据的图?带上主键唯一键。 可以看看 tidb 的 audit log,看看 sql 是啥样。或者你拉这边的 debug 分支,日志开 debug 级别,看看输出的 sql 长啥样。 这种情况似乎只有 replace 不带 updated at 这列才可能发生。但非空列程序不会自己去删,有配置删掉这列吗?

smilenazy commented 4 years ago

我这边也碰到这个问题了。。。 datetime 字段 DEFAULT CURRENT_TIMESTAMP 发现日期被刷新了

然后同样还有一个datetime字段 没default值 就完全OK

smilenazy commented 4 years ago

刚去确定了下 , 问题出在运用了default 值 , SQL 传入是default 这个看来要从代码层面解决?

Ryan-Git commented 4 years ago

刚去确定了下 , 问题出在运用了default 值 , SQL 传入是default 这个看来要从代码层面解决?

我用下面的表试了一下没复现。能不能给个复现的例子?

CREATE TABLE `ttt` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `v` int(11) NOT NULL,
  `add_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录修改日期',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_v` (`v`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
Ryan-Git commented 4 years ago

代码里只有生成列和源端 binlog 没有这一列的情况才会填 default

smilenazy commented 4 years ago

代码里只有生成列和源端 binlog 没有这一列的情况才会填 default

我晚点给你把binlog截取下,我这边的架构是几个库多源复制到汇总库,然后通过gravity做归档库同步的测试。

smilenazy commented 4 years ago

代码里只有生成列和源端 binlog 没有这一列的情况才会填 default

-- 源端 binlog INSERT INTO t_ticket_bet_order (order_id, bet_time, update_at, plan_sales_start_time, tester) VALUES (1276304325068455954, '2020-06-26 08:00:38.0', '2020-06-26 08:00:38.0', '2020-06-26 07:59:55.0', 0), (1276304325085233243, '2020-06-26 08:00:38.0', '2020-06-26 08:00:38.0', '2020-06-26 07:59:55.0', 0);

-- 归档 binlog -- 归档表数据基本和tidb一致 只不过update_at时间有秒级别偏差 可能自己测试机器性能导致应用时间偏差

REPLACE INTO test.t_ticket_bet_order (order_id, bet_time, update_at, deducted, plan_sales_start_time) VALUES (1276304325068455954, '2020-06-26 08:00:38', DEFAULT, 0, '2020-06-26 07:59:55'); REPLACE INTO test.t_ticket_bet_order (order_id, bet_time, update_at, deducted, plan_sales_start_time) VALUES (1276304325085233243, '2020-06-26 08:00:38', DEFAULT, 0, '2020-06-26 07:59:55');

-- tidb 表数据

+---------------------+---------------------+---------------------+----------+-----------------------+ | order_id | bet_time | update_at | deducted | plan_sales_start_time | +---------------------+---------------------+---------------------+----------+-----------------------+ | 1276304325068455954 | 2020-06-26 08:00:38 | 2020-06-26 13:21:02 | 0 | 2020-06-26 07:59:55 | | 1276304325085233243 | 2020-06-26 08:00:38 | 2020-06-26 13:21:03 | 0 | 2020-06-26 07:59:55 | +---------------------+---------------------+---------------------+----------+-----------------------+ 2 rows in set (0.00 sec)

create table t_ticket_bet_order ( order_id bigint(20) NOT NULL, bet_time datetime NOT NULL, update_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deducted tinyint(1) NOT NULL DEFAULT '0' , plan_sales_start_time datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , PRIMARY KEY (order_id));

smilenazy commented 4 years ago

我确实无法理解。。。 源端BINLOG里还是时间 再gravity传输过后就变成了default。。。3个架构表结构一致

zhanjianS commented 4 years ago

@Ryan-Git 非常抱歉 之前没注意到信息,现在不在公司有点不好看tidb的日志和重新拉取 说下几点情况: 1、没有进行数据列的过滤, 2、数据是有主键的 另外有一个现象 tidb端的表结构 在update_at去掉ON UPDATE CURRENT_TIMESTAMP属性时,进行mysql->tidb 数据重新同步时,数据是正常的,时间不会发生改变

Ryan-Git commented 4 years ago

代码里只有生成列和源端 binlog 没有这一列的情况才会填 default

-- 源端 binlog INSERT INTO t_ticket_bet_order (order_id, bet_time, update_at, plan_sales_start_time, tester) VALUES (1276304325068455954, '2020-06-26 08:00:38.0', '2020-06-26 08:00:38.0', '2020-06-26 07:59:55.0', 0), (1276304325085233243, '2020-06-26 08:00:38.0', '2020-06-26 08:00:38.0', '2020-06-26 07:59:55.0', 0);

-- 归档 binlog -- 归档表数据基本和tidb一致 只不过update_at时间有秒级别偏差 可能自己测试机器性能导致应用时间偏差

REPLACE INTO test.t_ticket_bet_order (order_id, bet_time, update_at, deducted, plan_sales_start_time) VALUES (1276304325068455954, '2020-06-26 08:00:38', DEFAULT, 0, '2020-06-26 07:59:55'); REPLACE INTO test.t_ticket_bet_order (order_id, bet_time, update_at, deducted, plan_sales_start_time) VALUES (1276304325085233243, '2020-06-26 08:00:38', DEFAULT, 0, '2020-06-26 07:59:55');

-- tidb 表数据

+---------------------+---------------------+---------------------+----------+-----------------------+ | order_id | bet_time | update_at | deducted | plan_sales_start_time | +---------------------+---------------------+---------------------+----------+-----------------------+ | 1276304325068455954 | 2020-06-26 08:00:38 | 2020-06-26 13:21:02 | 0 | 2020-06-26 07:59:55 | | 1276304325085233243 | 2020-06-26 08:00:38 | 2020-06-26 13:21:03 | 0 | 2020-06-26 07:59:55 | +---------------------+---------------------+---------------------+----------+-----------------------+ 2 rows in set (0.00 sec)

create table t_ticket_bet_order ( order_id bigint(20) NOT NULL, bet_time datetime NOT NULL, update_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deducted tinyint(1) NOT NULL DEFAULT '0' , plan_sales_start_time datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , PRIMARY KEY (order_id));

这个我还是重现不了。。。能给个重新步骤?MySQL版本是啥? 有几个怀疑的地方,

@zhanjianS 也看下源端和目标端的 show columns from

Ryan-Git commented 4 years ago

问题是TiDB某些版本对这种列的描述是DEFAULT_GENERATED,跟MySQL不一致,被gravity当做MySQL的生成列处理了。 影响的是目标端是TiDB的带DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP的列,跟全量还是增量没关系。(当然增量情况下只要不延迟这个影响其实很小) 我修一下。

| update_time           | datetime            | NO   |      | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP |
smilenazy commented 4 years ago

代码里只有生成列和源端 binlog 没有这一列的情况才会填 default

-- 源端 binlog INSERT INTO t_ticket_bet_order (order_id, bet_time, update_at, plan_sales_start_time, tester) VALUES (1276304325068455954, '2020-06-26 08:00:38.0', '2020-06-26 08:00:38.0', '2020-06-26 07:59:55.0', 0), (1276304325085233243, '2020-06-26 08:00:38.0', '2020-06-26 08:00:38.0', '2020-06-26 07:59:55.0', 0); -- 归档 binlog -- 归档表数据基本和tidb一致 只不过update_at时间有秒级别偏差 可能自己测试机器性能导致应用时间偏差 REPLACE INTO test.t_ticket_bet_order (order_id, bet_time, update_at, deducted, plan_sales_start_time) VALUES (1276304325068455954, '2020-06-26 08:00:38', DEFAULT, 0, '2020-06-26 07:59:55'); REPLACE INTO test.t_ticket_bet_order (order_id, bet_time, update_at, deducted, plan_sales_start_time) VALUES (1276304325085233243, '2020-06-26 08:00:38', DEFAULT, 0, '2020-06-26 07:59:55'); -- tidb 表数据 +---------------------+---------------------+---------------------+----------+-----------------------+ | order_id | bet_time | update_at | deducted | plan_sales_start_time | +---------------------+---------------------+---------------------+----------+-----------------------+ | 1276304325068455954 | 2020-06-26 08:00:38 | 2020-06-26 13:21:02 | 0 | 2020-06-26 07:59:55 | | 1276304325085233243 | 2020-06-26 08:00:38 | 2020-06-26 13:21:03 | 0 | 2020-06-26 07:59:55 | +---------------------+---------------------+---------------------+----------+-----------------------+ 2 rows in set (0.00 sec) create table t_ticket_bet_order ( order_id bigint(20) NOT NULL, bet_time datetime NOT NULL, update_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deducted tinyint(1) NOT NULL DEFAULT '0' , plan_sales_start_time datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , PRIMARY KEY (order_id));

这个我还是重现不了。。。能给个重新步骤?MySQL版本是啥? 有几个怀疑的地方,

  • 看下源端 show columns from t_ticket_bet_order,源端这个tester怎么处理的?
  • 看下目标端 show columns from t_ticket_bet_order,结果里列名大小写和源端一样吗?

@zhanjianS 也看下源端和目标端的 show columns from

表结构完全一致

对了 我中间是 M => M => Tidb 并不是直接TIDB 中间M=>M也是有这个问题的

zhanjianS commented 4 years ago

代码里只有生成列和源端 binlog 没有这一列的情况才会填 default

-- 源端 binlog INSERT INTO t_ticket_bet_order (order_id, bet_time, update_at, plan_sales_start_time, tester) VALUES (1276304325068455954, '2020-06-26 08:00:38.0', '2020-06-26 08:00:38.0', '2020-06-26 07:59:55.0', 0), (1276304325085233243, '2020-06-26 08:00:38.0', '2020-06-26 08:00:38.0', '2020-06-26 07:59:55.0', 0); -- 归档 binlog -- 归档表数据基本和tidb一致 只不过update_at时间有秒级别偏差 可能自己测试机器性能导致应用时间偏差 REPLACE INTO test.t_ticket_bet_order (order_id, bet_time, update_at, deducted, plan_sales_start_time) VALUES (1276304325068455954, '2020-06-26 08:00:38', DEFAULT, 0, '2020-06-26 07:59:55'); REPLACE INTO test.t_ticket_bet_order (order_id, bet_time, update_at, deducted, plan_sales_start_time) VALUES (1276304325085233243, '2020-06-26 08:00:38', DEFAULT, 0, '2020-06-26 07:59:55'); -- tidb 表数据 +---------------------+---------------------+---------------------+----------+-----------------------+ | order_id | bet_time | update_at | deducted | plan_sales_start_time | +---------------------+---------------------+---------------------+----------+-----------------------+ | 1276304325068455954 | 2020-06-26 08:00:38 | 2020-06-26 13:21:02 | 0 | 2020-06-26 07:59:55 | | 1276304325085233243 | 2020-06-26 08:00:38 | 2020-06-26 13:21:03 | 0 | 2020-06-26 07:59:55 | +---------------------+---------------------+---------------------+----------+-----------------------+ 2 rows in set (0.00 sec) create table t_ticket_bet_order ( order_id bigint(20) NOT NULL, bet_time datetime NOT NULL, update_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deducted tinyint(1) NOT NULL DEFAULT '0' , plan_sales_start_time datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , PRIMARY KEY (order_id));

这个我还是重现不了。。。能给个重新步骤?MySQL版本是啥? 有几个怀疑的地方,

* 看下源端 show columns from t_ticket_bet_order,源端这个`tester`怎么处理的?

* 看下目标端 show columns from t_ticket_bet_order,结果里列名大小写和源端一样吗?

@zhanjianS 也看下源端和目标端的 show columns from

源端跟目标端结构 表结构都是这个,这边的字段类型是timestamp 图片

Ryan-Git commented 4 years ago

@smilenazy @zhanjianS 试一下新版本?

zhanjianS commented 4 years ago

已经可以了