percona-toolkit之pt-table-checksum的简易操作实验
网址链接:https://www.percona.com/doc/percona-toolkit/LATEST/pt-table-checksum.html
一.工作原理
- 连接到主库:pt工具连接到主库,然后自动发现主库的所有从库。默认采用show full processlist来查找从库,但是这只有在主从实例端口相同的情况下才有效。
- 查找主库或者从库是否有复制过滤规则:这是为了安全而默认检查的选项。你可以关闭这个检查,但是这可能导致checksum的sql语句要么不会同步到从库,要么到了从库发现从库没有要被checksum的表,这都会导致从库同步卡库。
- 开始获取表,一个个的计算。
- 如果是表的第一个chunk,那么chunk-size一般为1000;如果不是表的第一个chunk,那么采用11步中分析出的结果。
- 检查表结构,进行数据类型转换等,生成checksum的sql语句。
- 根据表上的索引和数据的分布,选择最合适的split表的方法。
- 开始checksum表。
- 默认在chunk一个表之前,先删除上次这个表相关的计算结果。除非–resume。
- 根据explain的结果,判断chunk的size是否超过了你定义的chunk-size的上限。如果超过了,为了不影响线上性能,这个chunk将被忽略。
- 把要checksum的行加上for update锁,并计算。把计算结果存储到master_crc master_count列中。计算方法为把所需检查的块中所有列的值拼接为一个长的字段,默认使用crc32算法来进行数据校验
- 调整下一个chunk的大小。
- 等待从库追上主库。如果没有延迟备份的从库在运行,最好检查所有的从库,如果发现延迟最大的从库延迟超过max-lag秒,pt工具在这里将暂停。
- 如果发现主库的max-load超过某个阈值,pt工具在这里将暂停。
- 继续下一个chunk,直到这个table被chunk完毕。
- 等待从库执行完checksum,便于生成汇总的统计结果。每个表汇总并统计一次。
- 循环每个表,直到结束。
二.安全性保障
1.pt-table-checksum一次只针对一个表,而且会根据表的大小以及当前系统的繁忙程度,计算出一次检查中能包含的数据行数,来尽量避免对线上服务的影响,如果在执行过程中遇到突发的负载增加,还会自动的将检查停下来等待,所以即使面对成千上万的数据库和表时,它也能顺利的进行检查
2.在检查过程中,工具会随时对主从连接情况进行检查,如果从库延迟太大,主从复制中断,检查会停下来等待;这里需要注意的是主从复制过滤,因为这种情形下,主从数据库中的库表存在情况不一致,检查过程中的执行语句会与当前的主从复制过程冲突导致主从复制进程失败,所以如果有过滤存在,需要指定参数--no-check-replication-filters
3.在一个块的数据被检查之前,会先执行explain操作,来确定执行该检查的安全性,如果太大不能在指定时间内完成检查的话就会将该块数据跳过,另外,如果主库上整表的数据特别少或干脆是空表,并不会直接将整表当做一个块去检查,而是会再去从库,确定从库中也是有同样少的数据,避免从库表数据太多却被当成一个块执行造成的从库数据阻塞
4.另外还有一些安全保护设置,在上面的执行流程中已经列出来了,如设置innodb_lock_wait_timeout=1,如果锁等待超过1S,就放弃此次执行
5.在执行过程中如果遇到任何异常,可随时中断进程,如kill或CTRL-C,不会造成任何影响,后面想从此次中断继续检查时,简单的采用--resume就可以
三.主要的一些参数
1 --check-binlog-format
因此工具要求的二进制日志记录格式为语句模式,二进制日志为行模式执行时会报错,使用此参数后不会报错
2 --chunk-size
指定一个数据块的大小,默认为1000行
3 --databases
指定需要被校验的数据库,数据库之间以逗号分隔
4 --databases-regex
仅叫校验名称匹配的数据库,后面需要添加Perl正则表达式
5 --engines
仅校验指定存储引擎的表
6 --ignore-databases
忽略此逗号分隔的数据库列表。
7--ignore-databases-regex
忽略名称与该Perl正则表达式匹配的数据库。
8 --ignore-engines
忽略此逗号分隔的存储引擎列表。
9 --ignore-tables
忽略此逗号分隔的表列表。表名可以使用数据库名来限定。该--replicate表总是自动被忽略。
10 --ignore-tables-regex
忽略名称与Perl正则表达式匹配的表
11 --replicate-check-retries
遇到差异时,请重试校验和比较多次。仅在此数量的检查之后差异仍然存在时,才认为它是有效的。如果将此选项的值设置为2或更大,则可以减轻使用–resume选项时出现的虚假差异。
更多参数请看上面的网址
四. 工具的安装
1.安装所需要的的依赖包
yum install -y perl perl-devel perl-Time-HiRes perl-DBI perl-DBD-MySQL
yum -y install perl-Digest-MD5
2.下载程序的软件包
wget http://www.percona.com/get/percona-toolkit.tar.gz
3.程序的安装
tar zxvf percona-toolkit.tar.gz
cd percona-toolkit-3.2.0/
tar zxvf percona-toolkit.tar.gz
make && make install
五。建议的操作实验
1.实验环境
mysql主从架构
主ip 10.0.0.51
从ip 10.0.0.52
2.在主库创建所需要的用户
GRANT all privileges ON *.* TO 'checksums'@'10.0.0.5%' IDENTIFIED BY '123';
flush privileges;
3.创建校验数据所需要的写入的数据库和表
mysql> create database percona;
Query OK, 1 row affected (0.02 sec)
mysql> use percona
Database changed
mysql> CREATE TABLE `checksums` (
-> `db` char(64) NOT NULL,
-> `tbl` char(64) NOT NULL,
-> `chunk` int(11) NOT NULL,
-> `chunk_time` float DEFAULT NULL,
-> `chunk_index` varchar(200) DEFAULT NULL,
-> `lower_boundary` text,
-> `upper_boundary` text,
-> `this_crc` char(40) NOT NULL,
-> `this_cnt` int(11) NOT NULL,
-> `master_crc` char(40) DEFAULT NULL,
-> `master_cnt` int(11) DEFAULT NULL,
-> `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-> PRIMARY KEY (`db`,`tbl`,`chunk`),
-> KEY `ts_db_tbl` (`ts`,`db`,`tbl`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.60 sec)
4.创建被校验的数据库和表
mysql> create database zxc;
Query OK, 1 row affected (0.00 sec)
mysql> use zxc;
Database changed
mysql> create table t(id tinyint primary key auto_increment,ename varchar(20));
Query OK, 0 rows affected (0.14 sec)
mysql> insert into t(ename) values('Leshami'),('Henry'),('Jack');
Query OK, 3 rows affected (0.07 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from t;
+----+---------+
| id | ename |
+----+---------+
| 1 | Leshami |
| 2 | Henry |
| 3 | Jack |
+----+---------+
3 rows in set (0.07 sec)
5.模拟主从一致的情况
主库执行
[root@db01 ~]# pt-table-checksum --nocheck-binlog-format --nocheck-replication-filters --recursion-method=hosts --replicate=percona.checksums --databases=zxc --host=10.0.0.51 --port=3306 --user=checksums --password=123
Checking if all tables can be checksummed ...
Starting checksum ...
Diffs cannot be detected because no slaves were found. Please read the --recursion-method documentation for information.
TS ERRORS DIFFS ROWS DIFF_ROWS CHUNKS SKIPPED TIME TABLE
06-30T15:50:50 0 0 3 0 1 0 0.255 zxc.t
登录从库进行校验
mysql> select * from percona.checksums where master_cnt <> this_cnt or master_crc <> this_crc;
Empty set (0.00 sec)
结果为空表示主从一致
6.模拟主从不一致的情况
再从库执行
mysql> insert into zxc.t(ename) value('zxc');
Query OK, 1 row affected (0.37 sec)
mysql> select * from zxc.t;
+----+---------+
| id | ename |
+----+---------+
| 1 | Leshami |
| 2 | Henry |
| 3 | Jack |
| 4 | zxc |
+----+---------+
4 rows in set (0.00 sec)
在主库从新进行校验
[root@db01 ~]# pt-table-checksum --nocheck-binlog-format --nocheck-replication-filters --recursion-method=hosts --replicate=percona.checksums --databases=zxc --host=10.0.0.51 --port=3306 --user=checksums --password=123
Checking if all tables can be checksummed ...
Starting checksum ...
Diffs cannot be detected because no slaves were found. Please read the --recursion-method documentation for information.
TS ERRORS DIFFS ROWS DIFF_ROWS CHUNKS SKIPPED TIME TABLE
06-30T16:03:51 0 0 3 0 1 0 0.006 zxc.t
在从库进行校验
mysql> select * from percona.checksums where master_cnt <> this_cnt or master_crc <> this_crc;
+-----+-----+-------+------------+-------------+----------------+----------------+----------+----------+------------+------------+---------------------+
| db | tbl | chunk | chunk_time | chunk_index | lower_boundary | upper_boundary | this_crc | this_cnt | master_crc | master_cnt | ts |
+-----+-----+-------+------------+-------------+----------------+----------------+----------+----------+------------+------------+---------------------+
| zxc | t | 1 | 0.001245 | NULL | NULL | NULL | 77d04490 | 4 | f8a02f9e | 3 | 2020-06-30 16:03:51 |
+-----+-----+-------+------------+-------------+----------------+----------------+----------+----------+------------+------------+---------------------+
1 row in set (0.00 sec)
会显示为t这个表有不一致的情况
6.目前发现存在的缺陷
首先先回复为主从一致的情况
mysql> delete from zxc.t where id=4;
Query OK, 1 row affected (0.00 sec)
mysql> select * from zxc.t;
+----+---------+
| id | ename |
+----+---------+
| 1 | Leshami |
| 2 | Henry |
| 3 | Jack |
+----+---------+
3 rows in set (0.00 sec)
在从库表中添加一个空列
mysql> alter table zxc.t add sex int;
Query OK, 0 rows affected (0.28 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> select * from zxc.t;
+----+---------+------+
| id | ename | sex |
+----+---------+------+
| 1 | Leshami | NULL |
| 2 | Henry | NULL |
| 3 | Jack | NULL |
+----+---------+------+
3 rows in set (0.00 sec)
主库进行重新校验
[root@db01 ~]# pt-table-checksum --nocheck-binlog-format --nocheck-replication-filters --recursion-method=hosts --replicate=percona.checksums --databases=zxc --host=10.0.0.51 --port=3306 --user=checksums --password=123
Checking if all tables can be checksummed ...
Starting checksum ...
Diffs cannot be detected because no slaves were found. Please read the --recursion-method documentation for information.
TS ERRORS DIFFS ROWS DIFF_ROWS CHUNKS SKIPPED TIME TABLE
06-30T16:14:44 0 0 3 0 1 0 0.006 zxc.t
从库进行查询结果
mysql> select * from percona.checksums where master_cnt <> this_cnt or master_crc <> this_crc;
Empty set (0.00 sec)
虽然现在从库的表已经添加了一列,不完全一致,但是此工具仍然认为主从是一致的,这可能跟工具的原理有关,因为把所有列拼接为长子串的时候,空列不会影响md5值得运算结果,需要看这个工具后续更新会不会解决这个问题