当前位置:网站首页>sync-diff-inspector 使用实践
sync-diff-inspector 使用实践
2022-08-04 08:58:00 【TiDB社区干货传送门】
作者: banana_jian 原文来源:https://tidb.net/blog/7ffd821a
简介
在数据同步的场景下,上下游数据的一致性校验是非常重要的一个环节,缺少数据校验,在某种程度上甚至可以说名整个数据同步是无效的。sync-diff-inspector 是一个用于校验 MySQL/TiDB 中两份数据是否一致的工具。该工具提供了修复数据的功能(适用于修复少量不一致的数据)。首先我们看下 Sync-diff-inspector 的架构图,了解一下 Sync-diff-inspector 的作用和实现原。
主要功能
对比表结构和数据
如果数据不一致,则生成用于修复数据的 SQL 语句
支持不同库名或表名的数据校验
支持分库分表场景下的数据校验
支持 TiDB 主从集群的数据校验
支持从 TiDB DM 拉取配置的数据校验
工具下载
https://download.pingcap.org/tidb-community-toolkit-v6.1.0-linux-amd64.tar.gz
[tidb@jian tidb-community-toolkit-v6.1.0-linux-amd64]$ pwd
/home/tidb/tidb-community-toolkit-v6.1.0-linux-amd64
[tidb@jian tidb-community-toolkit-v6.1.0-linux-amd64]$ ls sync_diff_inspector
sync_diff_inspector
数据库用户创建
sync-diff-inspector 需要获取表结构信息、查询数据,需要的数据库权限如下:
源端的目标端的权限需求是一样的
([email protected]) [jian] 16:44:25> create user [email protected]'%' identified by '123456';Query OK, 0 rows affected (0.04 sec)([email protected]) [jian] 16:44:41> grant show databases,reload,select on *.* to [email protected]'%';Query OK, 0 rows affected (0.40 sec)
实践
1 对比源端和目标端的同一张表
数据状态
源端: 目标端:
([email protected]) [jian] 16:55:48> select * from jian.jiantb; ([email protected]) [jian] 16:53:32> select * from jian.jiantb;
+------+------+ +------+------+
| id | name | | id | name |
+------+------+ +------+------+
| 1 | a | | 1 | a |
| 2 | a | | 2 | a |
| 3 | a | +------+------+
+------+------+
对于以上的数据情况我们期望看到的结果是检查数据一致性失败,并且提供sql可以插入目标端不存在的数据(3,‘a’)
配置文件
export-fix-sql = truecheck-struct-only = false[data-sources][data-sources.mysql1] host = "192.168.135.149" port = 3306 user = "root" password = "123456"[data-sources.tidb0] host = "127.0.0.1" port = 4000 user = "root" password = "123456"[task] output-dir = "./output" source-instances = ["mysql1"] target-instance = "tidb0" target-check-tables = ["jian.jiantb"]
执行校验
[[email protected] ~]$ sync_diff_inspector --config=sync_check
A total of 1 tables need to be compared
Comparing the table structure of ``jian`.`jiantb`` ... equivalent
Comparing the table data of ``jian`.`jiantb`` ... failure
_____________________________________________________________________________
Progress [============================================================>] 100% 0/0
The data of `jian`.`jiantb` is not equal
The rest of tables are all equal.
The patch file has been generated in
'output/fix-on-tidb0/'
You can view the comparision details through './output/sync_diff.log'
修复sql查看
[[email protected] ~]$ cat output/fix-on-tidb0/jian\:jiantb\:0\:0-0\:0.sql
-- table: jian.jiantb
-- range in sequence: Full
REPLACE INTO `jian`.`jiantb`(`id`,`name`) VALUES (3,'a');
2 源端和目标端的表名不同
数据状态
源端: 目标端:
([email protected]) [jian] 16:55:48> select * from jian.yao; ([email protected]) [jian] 16:53:32> select * from jian.jiantb;
+------+------+ +------+------+
| id | name | | id | name |
+------+------+ +------+------+
| 1 | a | | 1 | a |
+------+------+ | 2 | a |
+------+------+
对于以上的数据情况我们期望看到的结果是,检查出jian.yao和jian.jiantb两张不同表名的表检查数据一致性失败,并且提供sql可以删除源端不存在的数据(2,‘a’)
配置文件
export-fix-sql = truecheck-struct-only = false[data-sources][data-sources.mysql1] host = "192.168.135.149" port = 3306 user = "root" password = "123456" route-rules = ["rule1"][data-sources.tidb0] host = "127.0.0.1" port = 4000 user = "root" password = "123456"[routes][routes.rule1]schema-pattern = "jian"table-pattern = "yao"target-schema = "jian"target-table = "jiantb"[task] output-dir = "./output" source-instances = ["mysql1"] target-instance = "tidb0" target-check-tables = ["jian.jiantb"]
执行校验
[[email protected] ~]$ sync_diff_inspector --config=sync_check2
A total of 1 tables need to be compared
Comparing the table structure of ``jian`.`jiantb`` ... equivalent
Comparing the table data of ``jian`.`jiantb`` ... failure
_____________________________________________________________________________
Progress [============================================================>] 100% 0/0
The data of `jian`.`jiantb` is not equal
The rest of tables are all equal.
The patch file has been generated in
'output/fix-on-tidb0/'
You can view the comparision details through './output/sync_diff.log'
修复sql查看
[[email protected] ~]$ cat output/fix-on-tidb0/jian\:jiantb\:0\:0-0\:0.sql
-- table: jian.jiantb
-- range in sequence: Full
DELETE FROM `jian`.`jiantb` WHERE `id` = 2 AND `name` = 'a' LIMIT 1;
3 对比时指定条件范围
数据状态
源端: 目标端:
([email protected]) [jian] 18:10:51> select * from jiantb; ([email protected]) [jian] 18:10:51> select * from jiantb;
+------+ +------+
| id | | id |
+------+ +------+
| 10 | | 10 |
| 20 | | 11 |
| 30 | | 20 |
| 26 | | 30 |
对于以上的数据情况我们期望看到的结果是,检查数据一致性失败,并且提供sql可以插入目标端不存在的数据(26),但是对于目标端比源端多出的11不希望生成删除的sql,因为我们在配置文件中指定了只检查id>20的部分数据。
配置文件
export-fix-sql = truecheck-struct-only = false[data-sources][data-sources.mysql1] host = "192.168.135.149" port = 3306 user = "root" password = "123456"[data-sources.tidb0] host = "127.0.0.1" port = 4000 user = "root" password = "123456"[task] output-dir = "./output" source-instances = ["mysql1"] target-instance = "tidb0" target-check-tables = ["jian.\*"] target-configs = ["config1"][table-configs.config1]target-tables=["jian.jiantb"]range = "id > 20"
执行校验
[[email protected] ~]$ ./tidb-community-toolkit-v6.1.0-linux-amd64/sync_diff_inspector --config=sync_check3
A total of 1 tables need to be compared
Comparing the table structure of ``jian`.`jiantb`` ... equivalent
Comparing the table data of ``jian`.`jiantb`` ... failure
_____________________________________________________________________________
Progress [============================================================>] 100%
The data of `jian`.`jiantb` is not equal
The rest of tables are all equal.
The patch file has been generated in
'output/fix-on-tidb0/'
You can view the comparision details through './output/sync_diff.log'
修复sql查看
[[email protected] ~]$ cat output/fix-on-tidb0/
jian:jiantb:0:0-0:0.sql .trash-2022-07-28T18:11:39+08:00/
[[email protected] ~]$ cat output/fix-on-tidb0/jian\:jiantb\:0\:0-0\:0.sql
-- table: jian.jiantb
-- range in sequence: Full
REPLACE INTO `jian`.`jiantb`(`id`) VALUES (26);
4 对比时数据存在部分不一致
数据状态
源端: 目标端:
([email protected]) [jian] 16:55:48> select * from jian.yao; ([email protected]) [jian] 16:53:32> select * from jian.jiantb;
+------+------+ +------+------+
| id | name | | id | name |
+------+------+ +------+------+
| 1 | a | | 1 | a |
| 2 | a | | 2 | b |
+------+------+ +------+------+
对于以上的数据情况我们期望看到的结果是,检查数据一致性失败,并且提供sql可以将目标端的错误数据(2,b)修正为(2,a)
配置文件
export-fix-sql = truecheck-struct-only = false[data-sources][data-sources.mysql1] host = "192.168.135.149" port = 3306 user = "root" password = "123456"[data-sources.tidb0] host = "127.0.0.1" port = 4000 user = "root" password = "123456"[task] output-dir = "./output" source-instances = ["mysql1"] target-instance = "tidb0" target-check-tables = ["jian.jiantb"]
执行校验
[[email protected] ~]$ ./tidb-community-toolkit-v6.1.0-linux-amd64/sync_diff_inspector --config=sync_check_1
A total of 1 tables need to be compared
Comparing the table structure of ``jian`.`jiantb`` ... equivalent
Comparing the table data of ``jian`.`jiantb`` ... failure
_____________________________________________________________________________
Progress [============================================================>] 100
The data of `jian`.`jiantb` is not equal
The rest of tables are all equal.
The patch file has been generated in
'output/fix-on-tidb0/'
You can view the comparision details through './output/sync_diff.log'
修复sql查看
[[email protected] ~]$ cat output/fix-on-tidb0/jian\:jiantb\:0\:0-0\:0.sql
-- table: jian.jiantb
-- range in sequence: Full
/*
DIFF COLUMNS ╏ `NAME`
╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍
source data ╏ 'a'
╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍
target data ╏ 'b'
╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╋╍╍╍╍╍╍╍╍╍
*/
REPLACE INTO `jian`.`jiantb`(`id`,`name`) VALUES (2,'a');
5 目标端的数据来自多个数据库
数据状态
源端: 目标端:
([email protected]) [jian] 16:55:48> select * from jian.yao; ([email protected]) [jian] 16:53:32> select * from jian.jiantb;
+------+------+ +------+------+
| id | name | | id | name |
+------+------+ +------+------+
| 1 | a | | 1 | a |
+------+------+ +------+------+
([email protected]) [jian] 10:37:57> select * from yao.yaotb; ([email protected]) [jian] 10:37:57> select * from yao.yaotb;
Empty set (0.01 sec) +----+------+
| id | name |
+----+------+
| 1 | a |
+----+------+
对于以上的数据情况我们期望看到的结果是,yao.yaotb检查数据一致性失败,jian.jiantb检查一致性通过,并且生成sql可以将目标端多余的数据(1,a)删除。
配置文件
export-fix-sql = truecheck-struct-only = false[data-sources][data-sources.mysql1] host = "192.168.135.149" port = 3306 user = "jian" password = "123456"[data-sources.mysql2] host = "127.0.0.1" port = 3306 user = "yao" password = "123456"[data-sources.tidb0] host = "127.0.0.1" port = 4000 user = "root" password = "123456"[task] output-dir = "./output" source-instances = ["mysql1","mysql2"] target-instance = "tidb0" target-check-tables = ["jian.jiantb","yao.yaotb"]
执行校验
[[email protected] ~]$ ./tidb-community-toolkit-v6.1.0-linux-amd64/sync_diff_inspector --config=sync_check
A total of 2 tables need to be compared
Comparing the table structure of ``jian`.`jiantb`` ... equivalent
Comparing the table data of ``jian`.`jiantb`` ... equivalent
Comparing the table structure of ``yao`.`yaotb`` ... equivalent
Comparing the table data of ``yao`.`yaotb`` ... failure
_____________________________________________________________________________
Progress [============================================================>] 100% 0/0
The data of `yao`.`yaotb` is not equal
The rest of tables are all equal.
The patch file has been generated in
'output/fix-on-tidb0/'
You can view the comparision details through './output/sync_diff.log'
修复sql查看
[[email protected] ~]$ cat output/fix-on-tidb0/yao\:yaotb\:0\:0-0\:0.sql
-- table: yao.yaotb
-- range in sequence: Full
DELETE FROM `yao`.`yaotb` WHERE `id` = 1 LIMIT 1;
校验信息
当校验结束时,sync-diff-inspector 会输出一份校验报告,位于 ${output}/summary.txt
中,其中 ${output}
是配置文件中 output-dir
的值。报告中会详细写出本次数据校验的参与对象,以及数据差异的详细信息,对比执行所消耗的时间以及速度。
[[email protected] ~]$ cat output/summary.txt
SummarySource Databasehost = "192.168.135.149"port = 3306user = "root"Target Databaseshost = "127.0.0.1"port = 4000user = "root"Comparison ResultThe table structure and data in following tables are equivalentThe following tables contains inconsistent data+-----------------+--------------------+----------------+---------+-----------+| TABLE | STRUCTURE EQUALITY | DATA DIFF ROWS | UPCOUNT | DOWNCOUNT |+-----------------+--------------------+----------------+---------+-----------+| `jian`.`jiantb` | true | +1/-1 | 2 | 2 |+-----------------+--------------------+----------------+---------+-----------+Time Cost: 39.521197msAverage Speed: 0.000000MB/s
几点解释
sync-diff-inspector 也可以只做表结构的检查相关参数是
check-struct-only
,默认情况下是false配置文件中datasource的定义的是无序的,只需要在task模块中指定对应的
source-instances
和target-instance
下游数据库缺失行,则是 REPLACE 语句, 可见上边的样例3 下游数据库冗余行,则是 DELETE 语句, 可见上边的样例2 下游数据库行部分数据不一致,则是 REPLACE 语句,但会在 SQL 文件中通过注释的方法标明不同的列, 可见上边的样例4
对于匹配规则,sync-diff-inspector支持通配符 "*" 和 "?"
使用限制
- 对于 MySQL 和 TiDB 之间的数据同步不支持在线校验,需要保证上下游校验的表中没有数据写入,或者保证某个范围内的数据不再变更,通过配置 range 来校验这个范围内的数据。
<!---->
- 不支持 JSON 类型的数据,在校验时需要设置 ignore-columns 忽略检查这些类型的数据。
<!---->
- FLOAT、DOUBLE 等浮点数类型在 TiDB 和 MySQL 中的实现方式不同,在计算 checksum 时会分别取 6 位和 15 位有效数字。如果不使用该特性,需要设置 ignore-columns 忽略这些列的检查。
<!---->
- 支持对不包含主键或者唯一索引的表进行校验,但是如果数据不一致,生成的用于修复的 SQL 可能无法正确修复数据。
注意事项
- sync-diff-inspector 在校验数据时会消耗一定的服务器资源,需要避免在业务高峰期间校验。
<!---->
- 在数据对比前,需要注意表中的 collation 设置。如果表的主键或唯一键为 varchar 类型,且上下游数据库中 collation 设置不同,可能会因为排序问题导致最终校验结果不正确,需要在 sync-diff-inspector 的配置文件中增加 collation 设置。
<!---->
- sync-diff-inspector 会优先使用 TiDB 的统计信息来划分 chunk,需要尽量保证统计信息精确,可以在业务空闲期手动执行
analyze table {table_name}
。
<!---->
table-rule 的规则需要特殊注意,例如设置了
schema-pattern="test1"
,table-pattern = "t_1"
,target-schema="test2"
,target-table = "t_2"
,会对比 source 中的表test1
.t_1
和 target 中的表test2
.t_2
。sync-diff-inspector 默认开启 sharding,如果 source 中还有表test2
.t_2
,则会把 source 端的表test1
.t_1
和表test2
.t_2
作为 sharding 与 target 中的表test2
.t_2
进行一致性校验。生成的 SQL 文件仅作为修复数据的参考,需要确认后再执行这些 SQL 修复数据。
总结
sync_diff_inspector是TiDB团队为了方便用户在MySQL数据迁移到TiDB后对数据一致性进行检查的开源工具,他不要求被检查的两个数据库之间存在任何的复制关系,并且对于表中是否存在索引也不会强制性要求,只要建立起对应的mapping关系即可以对两个数据库进行数据的一致性检验。如果sync_diff_inspector发现某个 chunk 的上下游的 checksum 不一致,可以通过二分法将原来的 chunk 划分成大小接近的两个子 chunk,对子 chunk 进行 checksum 对比,进一步缩小不一致行的可能范围。
虽然sync_diff_inspector目前还不能做到实时的数据一致性检验,但也提供类似range和snapshot等一些变相的方式来检查某一个特定“区域”的数据的一致性。
参考
https://docs.pingcap.com/zh/tidb/stable/sync-diff-inspector-overview
边栏推荐
猜你喜欢
图的基本概念
Anton Paar安东帕密度计比重计维修DMA35性能参数
【论文笔记】Understanding Long Programming Languages with Structure-Aware Sparse Attention
已解决No module named ‘flask_misaka‘【BUG解决】
金仓数据库 KDTS 迁移工具使用指南 (4. BS 版使用说明)
线程安全问题
redis分布式锁的实现
今年37了,被大厂抢着要...
RL学习笔记(一)
Recommend several methods that can directly translate PDF English documents
随机推荐
学会 Arthas,让你 3 年经验掌握 5 年功力
DeLighT:深度和轻量化的Transformer
Convert callback function to Flow
How to write patents are more likely to pass?
JMeter 常用的几种断言方法,你会几种呢?
将jpg图片转换成yuv420(NV12)数据文件
cannot import name ‘import_string‘ from ‘werkzeug‘【bug解决】
用OpenGL绘制winXP版扫雷的笑脸表情
秒懂大模型 | 3步搞定AI写摘要
2022-08-02 分析RK817 输出32k clock PMIC_32KOUT_WIFI给WiFi模块 clock 注册devm_clk_hw_register
金仓数据库KingbaseES客户端编程接口指南-JDBC(10. JDBC 读写分离最佳实践)
[Computer recording screen] How to use bandicam to record the game setting graphic tutorial
Grafana9.0发布,Prometheus和Loki查询生成器、全新导航、热图面板等新功能!
2022年制冷与空调设备运行操作特种作业证考试题库及模拟考试
四大网络攻击常见手段及防护
去掉js代码文件所有注释
关于#sql#的问题:后面换了一个数据库里面的数据就不能跑了
【NOI模拟赛】纸老虎博弈(博弈论SG函数,长链剖分)
如何设计一个注册中心
How to import data from PG to kingbaseES