千家信息网

如何使用percona-toolkit工具检查及修复MySQL数据库的主从不一致

发表于:2024-11-23 作者:千家信息网编辑
千家信息网最后更新 2024年11月23日,下文主要给大家带来如何使用percona-toolkit工具检查及修复MySQL数据库的主从不一致,希望这些内容能够带给大家实际用处,这也是我如何使用percona-toolkit工具检查及修复MyS
千家信息网最后更新 2024年11月23日如何使用percona-toolkit工具检查及修复MySQL数据库的主从不一致

下文主要给大家带来如何使用percona-toolkit工具检查及修复MySQL数据库的主从不一致,希望这些内容能够带给大家实际用处,这也是我如何使用percona-toolkit工具检查及修复MySQL数据库的主从不一致编辑这篇文章的主要目的。好了,废话不多说,大家直接看下文吧。

pt-table-checksum是Percona-Toolkit的组件之一,用于检测MySQL主、从库的数据是否一致。其原理是在主库执行基于statement的sql语句来生成主库数据块的checksum,把相同的sql语句传递到从库执行,并在从库上计算相同数据块的checksum,最后,比较主从库上相同数据块的checksum值,由此判断主从数据是否一致。检测过程根据唯一索引将表按row切分为块(chunk),以为单位计算,可以避免锁表。检测时会自动判断复制延迟、 master的负载, 超过阀值后会自动将检测暂停,减小对线上服务的影响。

pt-table-checksum默认情况下可以应对绝大部分场景,官方说,即使上千个库、上万亿的行,它依然可以很好的工作,这源自于设计很简单,一次检查一个表,不需要太多的内存和多余的操作;必要时,pt-table-checksum 会根据云服务器负载动态改变chunk大小,减少从库的延迟。

为了减少对数据库的干预,pt-table-checksum还会自动侦测并连接到从库,当然如果失败,可以指定--recursion-method选项来告诉从库在哪里。它的易用性还体现在,复制若有延迟,在从库checksum会暂停直到赶上主库的计算时间点(也通过选项--设定一个可容忍的延迟最大值,超过这个值也认为不一致)。

  • 为了保证主数据库服务的安全,该工具实现了许多保护措施:
    • 自动设置 innodb_lock_wait_timeout 为1s,避免引起
    • 默认当数据库有25个以上的并发查询时,pt-table-checksum会暂停。可以设置 --max-load 选项来设置这个阀值
    • 当用 Ctrl+C 停止任务后,工具会正常的完成当前 chunk 检测,下次使用 --resume 选项启动可以恢复继续下一个 chunk

2、工作过程

  • 1、连接到主库:pt工具连接到主库,然后自动发现主库的所有从库。默认采用show full processlist来查找从库,但是这只有在主从实例端口相同的情况下才有效。
  • 3、查找主库或者从库是否有复制过滤规则:这是为了安全而默认检查的选项。你可以关闭这个检查,但是这可能导致checksum的sql语句要么不会同步到从库,要么到了从库发现从库没有要被checksum的表,这都会导致从库同步卡库。
  • 5、开始获取表,一个个的计算。
  • 6、如果是表的第一个chunk,那么chunk-size一般为1000;如果不是表的第一个chunk,那么采用19步中分析出的结果。
  • 7、检查表结构,进行数据类型转换等,生成checksum的sql语句。
  • 8、根据表上的索引和数据的分布,选择最合适的split表的方法。
  • 9、开始checksum表。
  • 10、默认在chunk一个表之前,先删除上次这个表相关的计算结果。除非-resume。
  • 14、根据explain的结果,判断chunk的size是否超过了你定义的chunk-size的上限。如果超过了,为了不影响线上性能,这个chunk将被忽略。
  • 15、把要checksum的行加上for update锁,并计算。
  • 17-18、把计算结果存储到master_crc master_count列中。
  • 19、调整下一个chunk的大小。
  • 20、等待从库追上主库。如果没有延迟备份的从库在运行,最好检查所有的从库,如果发现延迟最大的从库延迟超过max-lag秒,pt工具在这里将暂停。
  • 21、如果发现主库的max-load超过某个阈值,pt工具在这里将暂停。
  • 22、继续下一个chunk,直到这个table被chunk完毕。
  • 23-24、等待从库执行完checksum,便于生成汇总的统计结果。每个表汇总并统计一次。
  • 25-26、循环每个表,直到结束。
    校验结束后,在每个从库上,执行如下的sql语句即可看到是否有主从不一致发生:
    select * from percona.checksums where master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc) \G

3、环境

IPPort主机名作用
192.168.1.1013306node1master
192.168.1.1023306node2slave
  • 注意事项:
    • 为了减少不必要的麻烦,确保你的 ptuser@'xxx' 用户能同时登陆主库和从库;
    • 只能指定一个host,必须为主库的IP;
    • 在检查时会向表加S锁;
    • 如果master和slave的binlog日志不是STATEMENT格式,要用--no-check-binlog-format选项
    • 运行之前需要从库的同步IO和SQL进程是YES状态。
    • 表要有主键索引或唯一键索引

4、下载

打开官网:https://www.percona.com/downloads/percona-toolkit/LATEST/
选择软件版本:Version,一般默认最新版即可;
选择系统版本:Software,也可以源码编译;我的CentOS6
系统架构:Hardware;我的64位;

我的下载为:
https://www.percona.com/downloads/percona-toolkit/3.0.13/binary/redhat/6/x86_64/percona-toolkit-debuginfo-3.0.13-1.el6.x86_64.rpm
https://www.percona.com/downloads/percona-toolkit/3.0.13/binary/redhat/6/x86_64/percona-toolkit-3.0.13-1.el6.x86_64.rpm

5、安装

yum install percona-toolkit-3.0.13-1.el6.x86_64.rpm -yyum install percona-toolkit-debuginfo-3.0.13-1.el6.x86_64.rpm -y
  • CentOS6.*依赖:

    perl-DBD-MySQLperl-DBIperl-IO-Socket-SSLperl-Net-LibIDNperl-Net-SSLeayperl-Time-HiRes
  • CentOS7.*依赖:
    perl-Compress-Raw-Bzip2perl-Compress-Raw-Zlibperl-DBD-MySQLperl-DBIperl-Digestperl-Digest-MD5perl-IO-Compressperl-IO-Socket-IPperl-IO-Socket-SSLperl-Mozilla-CAperl-Net-Daemonperl-Net-LibIDNperl-Net-SSLeayperl-PlRPC

查看安装的文件:

[root@node1 ~]# rpm -ql percona-toolkit/usr/bin/pt-align/usr/bin/pt-archiver/usr/bin/pt-config-diff/usr/bin/pt-deadlock-logger/usr/bin/pt-diskstats/usr/bin/pt-duplicate-key-checker/usr/bin/pt-fifo-split/usr/bin/pt-find/usr/bin/pt-fingerprint/usr/bin/pt-fk-error-logger/usr/bin/pt-heartbeat/usr/bin/pt-index-usage/usr/bin/pt-ioprofile/usr/bin/pt-kill/usr/bin/pt-mext/usr/bin/pt-mongodb-query-digest/usr/bin/pt-mongodb-summary/usr/bin/pt-mysql-summary/usr/bin/pt-online-schema-change/usr/bin/pt-pmp/usr/bin/pt-query-digest/usr/bin/pt-secure-collect/usr/bin/pt-show-grants/usr/bin/pt-sift/usr/bin/pt-slave-delay/usr/bin/pt-slave-find/usr/bin/pt-slave-restart/usr/bin/pt-stalk/usr/bin/pt-summary/usr/bin/pt-table-checksum     # 校验数据一致性;/usr/bin/pt-table-sync         # 修复不一致数据;/usr/bin/pt-table-usage/usr/bin/pt-upgrade/usr/bin/pt-variable-advisor/usr/bin/pt-visual-explain... ...[root@node1 ~]#

6、创建演示数据

6.1、主库master:

root@node1 10:56:  [(none)]> create database pt_check;Query OK, 1 row affected (0.04 sec)root@node1 10:57:  [(none)]> use pt_checkDatabase changedroot@node1 10:58:  [pt_check]> create table test1(id int auto_increment primary key,name varchar(20) not null);Query OK, 0 rows affected (0.86 sec)root@node1 11:03:  [pt_check]> insert into test1 values(null,'will');Query OK, 1 row affected (0.00 sec)root@node1 11:03:  [pt_check]> insert into test1 values(null,'jim');Query OK, 1 row affected (0.00 sec)root@node1 11:03:  [pt_check]> insert into test1 values(null,'tom');Query OK, 1 row affected (0.05 sec)root@node1 11:03:  [pt_check]> select * from pt_check.test1;+----+------+| id | name |+----+------+|  1 | will ||  2 | jim  ||  3 | tom  |+----+------+3 rows in set (0.00 sec)root@node1 11:04:  [pt_check]>

6.2、从库slave:

root@node1 11:03:  [pt_check]> select * from pt_check.test1;+----+------+| id | name |+----+------+|  1 | will ||  2 | jim  ||  3 | tom  |+----+------+3 rows in set (0.00 sec)root@node1 11:04:  [pt_check]> delete from pt_check.test1 where id='2';Query OK, 1 row affected (0.02 sec)root@node2 12:23:  [(none)]> select * from pt_check.test1;+----+------+| id | name |+----+------+|  1 | will ||  3 | tom  |+----+------+2 rows in set (0.00 sec)root@node2 12:23:  [(none)]>

6.3、创建校验用户

  • master
root@node1 12:28:  [pt_check]> GRANT CREATE,INSERT,SELECT,DELETE,UPDATE,LOCK TABLES,PROCESS,SUPER,REPLICATION SLAVE ON *.* TO 'ptuser'@'192.168.1.101' IDENTIFIED BY '123456';Query OK, 0 rows affected (0.00 sec)root@node1 12:29:  [pt_check]>  flush privileges;Query OK, 0 rows affected (0.00 sec)root@node1 12:29:  [pt_check]> select Host,User  from mysql.user;+----------------+---------------+| Host           | User          |+----------------+---------------+| localhost      | root          || localhost      | mysql.session || localhost      | mysql.sys     || 172.16.156.%   | rep           || %              | java          || 192.168.1.101 | ptuser        |+----------------+---------------+9 rows in set (0.00 sec)root@node1 12:29:  [pt_check]>
  • slave
root@node2 12:48:  [(none)]> select Host,User  from mysql.user;+----------------+---------------+| Host           | User          |+----------------+---------------+| localhost      | root          || localhost      | mysql.session || localhost      | mysql.sys     || 172.16.156.%   | rep           || %              | java          || 192.168.1.101 | ptuser        |+----------------+---------------+8 rows in set (0.00 sec)root@node2 12:48:  [(none)]>
  • 权限解释:
    • select //查看所有库的表,原理可加 explain选项查看
    • process //自动发现从库信息,show processlist
    • super //set binlog_format='statement'
    • replication slave //show slave hosts

7、pt-table-checksum校验

7.1、pt-table-checksum参数解释

  • --replicate-check:执行完 checksum 查询在percona.checksums表中,不一定马上查看结果呀 -- yes则马上比较chunk的crc32值并输出DIFFS列,否则不输出。默认yes,如果指定为--noreplicate-check,一般后续使用下面的--replicate-check-only去输出DIFF结果。
  • --nocheck-replication-filters :不检查复制过滤器,建议启用。后面可以用--databases来指定需要检查的数据库。
  • --no-check-binlog-format : 不检测日志格式。这个选项对于 ROW 模式的复制很重要,因为pt-table-checksum会在 Master和Slave 上设置binlog_format=STATEMENT(确保从库也会执行 checksum SQL),MySQL限制从库是无法设置的,所以假如行复制从库,再作为主库复制出新从库时(A->B->C),B的checksums数据将无法传输。(没验证)
  • --replicate-check-only :不在主从库做 checksum 查询,只在原有 percona.checksums 表中查询结果,并输出数据不一致的信息。周期性的检测一致性时可能用到。
  • --replicate= :把checksum的信息写入到指定表中,如果没有指定,默认是 percona.checksums ;建议直接写到被检查的数据库当中。
  • --databases=,-d :要检查的数据库,逗号分隔;--databases-regex 正则匹配要检测的数据库,--ignore-databases[-regex]忽略检查的库。Filter选项。
  • --tables=,-t
    :要检查的表,逗号分隔。如果要检查的表分布在不同的db中,可以用--tables=dbname1.table1,dbnamd2.table2的形式。同理有--tables-regex,--ignore-tables,--ignore-tables-regex。--replicate指定的checksum表始终会被过滤。
  • --tables= :指定需要被检查的表,多个用逗号隔开
  • h=192.168.1.101 :Master的地址
  • u=ptuser :用户名
  • p=123456 :密码
  • P=3306 :端口
  • --create-replicate-table 选项会自动创建 percona.checksums 表,但也意味着赋予额外的 CREATE TABLE权限给 percona_tk@'xxx' 用户。默认yes
  • --no-check-replication-filters 表示不需要检查 Master 配置里是否指定了 Filter。 默认会检查,如果配置了 Filter,如 replicate_do_db,replicate-wild-ignore-table,binlog_ignore_db 等,在从库checksum就与遇到表不存在而报错退出,所以官方默认是yes(--check-replication-filters)但我们实际在检测中时指定--databases=,所以就不存在这个问题,干脆不检测;
  • --empty-replicate-table:每个表checksum开始前,清空它之前的检测数据(不影响其它表的checksum数据),默认yes。当然如果使用--resume启动检测数据不会清空。当启用--noempty-replicate-table即不清空时,不计算计算chunk,只计算。
  • --recursion-method:发现从库的方式。pt-table-checksum 默认可以在主库的 processlist 中找到从库复制进程,从而识别出有哪些从库,但如果使用是非标准3306端口,会导致找不到从库信息。此时就会自动采用host方式,但需要提前在从库 my.cnf 里面配置report_host、report_port信息,如:

    report_host = MASTER_HOSTreport_port = 13306

    最终极的办法是dsn,dsn指定的是某个表(如 percona.dsns ),表行记录是改主库的(多个)从库的连接信息。适用以下任一情形:

  • 主库不能自动发现从库
  • 不想在从库添加额外配置(因为要重启)
  • 主从检测连接用户信息不一样
  • 多个从库时只想验证指定从库的一致

我比较倾向使用DSN的方式。这个dsns表只需要在执行 pt-table-checksum 命令的云服务器上能够访问到就行。这里纠正一个认识,网上很多人说 pt-table-checksum 要在主库上执行,其实不是的,我的mysql实例比较多,只需在某一台云服务器上安装percona-toolkit,这台服务能够同时访问主库和从库就行了。具体用法见后面实例。

7.2、在主库上执行数据检查命令

[root@node1 ~]# pt-table-checksum --nocheck-replication-filters --replicate=test.checksums --databases=pt_check --tables=test1 h=192.168.1.101,u=ptuser,p=123456,P=3306Checking if all tables can be checksummed ...Starting checksum ...Replica node2 has binlog_format ROW which could cause pt-table-checksum to break replication.  Please read "Replicas using row-based replication" in the LIMITATIONS section of the tool's documentation.  If you understand the risks, specify --no-check-binlog-format to disable this check.[root@node1 ~]#

从库node2的bbinlog日志为ROW,这可能导致pt-table-checksum中断复制。可以指定--no-check-binlog-format以禁用此检查。

[root@node1 ~]# pt-table-checksum --nocheck-replication-filters --replicate=test.checksums --databases=pt_check --tables=test1 h=192.168.1.101,u=ptuser,p=123456,P=3306 --no-check-binlog-formatChecking if all tables can be checksummed ...Starting checksum ...            TS ERRORS  DIFFS     ROWS  DIFF_ROWS  CHUNKS SKIPPED    TIME TABLE02-19T18:23:22      0      1        3          0       1       0   0.045 pt_check.test1[root@node1 ~]#
表示说明:
  • TS :完成检查的时间。
  • ERRORS :检查时候发生错误和警告的数量。
  • DIFFS :不一致的chunk数量。当指定 --no-replicate-check 即检查完但不立即输出结果时,会一直为0;当指定 --replicate-check-only 即不检查只从checksums表中计算crc32,且只显示不一致的信息(毕竟输出的大部分应该是一致的,容易造成干扰)。
  • ROWS :比对的表行数。
  • CHUNKS :被划分到表中的块的数目。
  • SKIPPED:由于错误或警告或过大,则跳过块的数目。
  • TIME :执行的时间。
  • TABLE :被检查的表名。

看到已经检查出主从数据有不一致了,DIFFS下的值为1,怎么不一致呢? 通过指定--replicate=test.checksums 参数,就说明把检查信息都写到了checksums表中

7.3、master的test.checksums表:

root@node1 09:19:  [(none)]> select * from test.checksums \G*************************** 1. row ***************************            db: pt_check           tbl: test1         chunk: 1    chunk_time: 0.005212   chunk_index: NULLlower_boundary: NULLupper_boundary: NULL      this_crc: b9a54161      this_cnt: 3                   # 本机 3行数据    master_crc: b9a54161    master_cnt: 3                   # master 3行数据            ts: 2019-02-20 09:18:011 row in set (0.00 sec)root@node1 09:19:  [(none)]>

7.4、slave的test.checksums表:

root@node2 09:20:  [(none)]> select * from test.checksums \G*************************** 1. row ***************************            db: pt_check           tbl: test1         chunk: 1    chunk_time: 0.005212   chunk_index: NULLlower_boundary: NULLupper_boundary: NULL      this_crc: d49ddeb7      this_cnt: 2                   # 本机 2行数据    master_crc: b9a54161    master_cnt: 3                   # master 3行数据            ts: 2019-02-20 09:18:011 row in set (0.01 sec)root@node2 09:20:  [(none)]>

8、pt-table-sync修复

8.1、打印数据的不同之处

master库用pt-table-sync命令和--print选项打印出master下的check_sum.test1和slave库的check_sum.test1的不一致的数据,如下:

[root@node1 ~]# pt-table-sync --replicate=test.checksums h=192.168.1.101,u=ptuser,p=123456,P=3306 h=192.168.1.102,u=ptuser,p=123456,P=3306 --printREPLACE INTO `pt_check`.`test1`(`id`, `name`) VALUES ('2', 'jim') /*percona-toolkit src_db:pt_check src_tbl:test1 src_dsn:P=3306,h=192.168.1.101,p=...,u=ptuser dst_db:pt_check dst_tbl:test1dst_dsn:P=3306,h=node2,p=...,u=ptuser lock:1 transaction:1 changing_src:test.checksums replicate:test.checksums bidirectional:0 pid:20377 user:root host:node1*/;[root@node1 ~]#
  • pt-table-sync参数说明:
--replicate=    :指定通过pt-table-checksum得到的表.--databases=    : 指定执行同步的数据库,多个用逗号隔开。--tables=       :指定执行同步的表,多个用逗号隔开。--sync-to-master :指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。h=127.0.0.1     :云服务器地址,命令里有2个ip,第一次出现的是Master的地址,第2次是Slave的地址。u=root          :帐号。p=123456        :密码。--print         :打印,但不执行命令。--execute       :执行命令。

8.2、pt-table-sync修复不同数据

接下的操作就是把slave上少的数据,从master同步过去(master操作);通过(--execute),让它们数据保持一致性:

[root@node1 ~]# pt-table-sync --replicate=test.checksums h=192.168.1.101,u=ptuser,p=123456,P=3306 h=192.168.1.102,u=ptuser,p=123456,P=3306 --execute

9、验证

9.1、使用pt-table-checksum重新校验:

[root@node1 ~]# pt-table-checksum --nocheck-replication-filters --replicate=test.checksums --databases=pt_check --tables=test1 h=192.168.1.101,u=ptuser,p=123456,P=3306 --no-check-binlog-formatChecking if all tables can be checksummed ...Starting checksum ...            TS ERRORS  DIFFS     ROWS  DIFF_ROWS  CHUNKS SKIPPED    TIME TABLE02-20T10:03:02      0      0        3          0       1       0   0.083 pt_check.test1[root@node1 ~]#

可以看到再次检查的时候,DIFFS已经是0了;

9.2、主库master:

root@node1 10:05:  [(none)]> select * from pt_check.test1;+----+------+| id | name |+----+------+|  1 | will ||  2 | jim  ||  3 | tom  |+----+------+3 rows in set (0.00 sec)root@node1 10:05:  [(none)]>

9.3、从库slave:

root@node2 10:02:  [(none)]> select * from pt_check.test1;+----+------+| id | name |+----+------+|  1 | will ||  2 | jim  ||  3 | tom  |+----+------+3 rows in set (0.00 sec)root@node2 10:05:  [(none)]>

已经跟master上的数据一致了。

10、报错

10.1、用户权限问题

没有创建CREATE表的权限;

[root@node1 ~]# pt-table-checksum --nocheck-replication-filters --replicate=test.checksums --databases=pt_check --tables=test1 h=192.168.1.101,u=ptuser,p=123456,P=3306 --no-check-binlog-formatChecking if all tables can be checksummed ...Starting checksum ...02-19T18:08:22 --create-replicate-table failed: DBD::mysql::db do failed: CREATE command denied to user 'ptuser'@'node1' for table 'checksums' [for Statement "  CREATE TABLE IF NOT EXISTS `test`.`checksums` (     db             CHAR(64)     NOT NULL,     tbl            CHAR(64)     NOT NULL,     chunk          INT          NOT NULL,     chunk_time     FLOAT            NULL,     chunk_index    VARCHAR(200)     NULL,     lower_boundary TEXT             NULL,     upper_boundary TEXT             NULL,     this_crc       CHAR(40)     NOT NULL,     this_cnt       INT          NOT NULL,     master_crc     CHAR(40)         NULL,     master_cnt     INT              NULL,     ts             TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,     PRIMARY KEY (db, tbl, chunk),     INDEX ts_db_tbl (ts, db, tbl)  ) ENGINE=InnoDB DEFAULT CHARSET=utf8"] at /usr/bin/pt-table-checksum line 12272.02-19T18:08:22 --replicate table checksums does not exist and it cannot be created automatically.  You need to create the table.[root@node1 ~]#

10.2、Diffs cannot be detected because no slaves were found

不能自动找到从库,确认processlist或host或dsns方式用对了。

10.3、Cannot connect to h=slave1.*.com,p=...,u=percona_user

可以在pt-table-checksum命令前加PTDEBUG=1来看详细的执行过程,如端口、用户名、权限错误。

10.4、Waiting for the --replicate table to replicate to XXX

问题出在 percona.checksums 表在从库不存在,根本原因是没有从主库同步过来,所以看一下从库是否延迟严重。

10.5、Pausing because Threads_running=25

反复打印出类似上面停止检查的信息。这是因为当前数据库正在运行的线程数大于默认25,pt-table-checksum 为了减少对库的压力暂停检查了。等数据库压力过了就好了,或者也可以直接 Ctrl+C 终端,下一次加上--resume继续执行,或者加大--max-load=值。

10.6、字符集问题

对于以上关于如何使用percona-toolkit工具检查及修复MySQL数据库的主从不一致,大家是不是觉得非常有帮助。如果需要了解更多内容,请继续关注我们的行业资讯,相信你会喜欢上这些内容的。

0