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


percona-toolkit是用perl开发的一系列的mysql工具集,今天着重记录在用于检查主从是否一致和修复数据上的使用。
安装相关的Perl依赖:
yum install perl-DBI perl-DBD-MySQL perl-TermReadKey perl-Time-HiRes perl-IO-Socket-SSL -y
先介绍一些关于二进制日志的知识
mysql binlog日志有三种格式,分别为Statement, Mixed,以及ROW。
1.Statement
每一条会修改数据的sql都会记录在binlog中。
优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。(相比row能节约多少性能与日志量,这个取决于应用的SQL情况,正常同一条记录修改或者插入row格式所产生的日志量还小于Statement产生的日志量,但是考虑到如果带条件的update操作,以及整表删除,alter表等操作,ROW格式会产生大量日志,因此在考虑是否使用ROW格式日志时应该跟据应用的实际情况,其所产生的日志量会增加多少,以及带来的IO性能问题。)
缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同 的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题(如sleep()函数, last_insert_id(),以及user-defined functions(udf)会出现问题).
2.Row
不记录sql语句上下文相关信息,仅保存哪条记录被修改。
优点:binlog中可以不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以rowlevel的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题
缺点:所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比如一条update语句,修改多条记录,则binlog中每一条修改都会有记录,这样造成binlog日志量会很大,特别是当执行alter table之类的语句的时候,由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中。
3.Mixed
是以上两种level的混合使用,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种.新版本的MySQL中队row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录。至于update或者delete等修改数据的语句,还是会记录所有行的变更。
pt-table-checksum在MASTER上校验指定库、表,将结果存在一个库表里,复制进程将检验sql传递到slave上再执行一次。通过比较主从的检验值确定数据是否一致。利用主从复制做检验,不需要在检验期间对主从数据库同时锁表,可以控制校验的数据和速度,不影响到正常服务。它通过在主库执行基于statement的sql语句来生成主库数据块的checksum,把相同的sql语句传递到从库,并在从库上计算相同数据块的checksum,最后比较主从库上相同数据块的checksum值,由此判断主从数据是否一致。这种校验是分表进行的,在每个表内部又是分块进行的,而且pt工具本身提供了非常多的限流选项,因此对线上服务的冲击较小。
在从机上制造相差数据
update content set hits=ceil(rand()*100) where id>=3060;
on master(0.81)
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=freeoa --tables=content h=192.168.0.83,u=dba,p=yourpaswd --empty-replicate-table --create-replicate-table
Failed to SET SESSION innodb_lock_wait_timeout=1: DBD::mysql::db do failed: Variable 'innodb_lock_wait_timeout' is a read only variable [for Statement "SET SESSION innodb_lock_wait_timeout=1"] at /usr/bin/pt-table-checksum line 6450.
The current innodb_lock_wait_timeout value 50 is greater than the --lock-wait-timeout value 1 and the variable cannot be changed. innodb_lock_wait_timeout is only dynamic when using the InnoDB plugin. To prevent this warning, either specify --lock-wait-time=50, or manually set innodb_lock_wait_timeout to a value less than or equal to 1 and restart MySQL.
You do not have the PROCESS privilege at /usr/bin/pt-table-checksum line 2759.
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=freeoa --tables=content h=192.168.0.83,u=dba,p=yourpaswd --empty-replicate-table --create-replicate-table --lock-wait-time=50
You do not have the PROCESS privilege at /usr/bin/pt-table-checksum line 2759.
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=freeoa --tables=content h=192.168.0.83,u=dba,p=yourpaswd --empty-replicate-table --create-replicate-table --lock-wait-time=50
=>
pt-table-checksum --nocheck-replication-filters --replicate=freeoa.checksum --databases=freeoa --tables=content u=root,p=1qaz2wsx,S=/tmp/mysql51.sock --empty-replicate-table --create-replicate-table --lock-wait-time=50
在从机上(0.83)
pt-table-sync --execute --replicate test.checksums --sync-to-master h=192.168.0.80,P=3306,u=dba,p=yourpaswd
pt-table-sync --print --execute --verbose --replicate freeoa.checksum --sync-to-master h=192.168.0.80,P=3306,u=dba,p=yourpaswd
登录从库执行:
SELECT * FROM freeoa.checksum WHERE master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);
返回若为空,则说明修复成功
=wzm表,记录数量:10000000
主机:
pt-table-checksum --nocheck-replication-filters --replicate=freeoa.checksum --databases=freeoa --tables=wzm u=root,p=1qaz2wsx,S=/tmp/mysql51.sock --empty-replicate-table --create-replicate-table --lock-wait-time=50
vbox虚拟机上1.7G的文件用时41s。
从机:
制造差异
update wzm set views=ceil(rand()*100) where cid between 328000000 and 328000900 and views<10;
开始重新同步:
pt-table-sync --print --execute --verbose --replicate freeoa.checksum --sync-to-master h=192.168.0.80,P=3306,u=dba,p=yourpaswd
pt-table-checksum --nocheck-replication-filters --replicate=newsclient_demo.checksum --databases=newsclient_demo u=dba,p=dbapasword,h=192.168.20.101,P=5113 --empty-replicate-table --create-replicate-table
do sql:
SELECT * FROM checksum WHERE master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);
SELECT * FROM test.checksum WHERE master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);
pt-table-checksum --nocheck-replication-filters --replicate=my_beta.checksum --databases=ym_beta u=dba,p=dbapasword,S=/tmp/mysql.sock --empty-replicate-table --create-replicate-table
为主从不同端口而设定:
CREATE TABLE `dsns` ( `id` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) DEFAULT NULL, `dsn` varchar(255) NOT NULL, PRIMARY KEY (`id`) );
--指定slave信息(如果有多个slave,就插入多条slave信息)
INSERT INTO dsns (parent_id,dsn) values(1,'h=192.168.20.114,u=dba,p=dbapasword,P=5133');
INSERT INTO dsns (parent_id,dsn) values(1,'h=192.168.20.182,u=dba,p=dbapasword,P=5133');
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum u=dba,p=dbapasword,S=/tmp/mysql.sock --empty-replicate-table --create-replicate-table --recursion-method=dsn=h=192.168.20.106,D=test,t=dsns --set-vars innodb_lock_wait_timeout=50 --databases=yqt
在从机上执行:
pt-table-sync --execute --verbose --replicate test.checksum --sync-to-master h=192.168.20.114,P=5133,u=dba,p=dbapasword --database=yqt
---------------------------------------------------------------
pt-table-checksum检查主从库数据的一致性
使用方法:
pt-table-checksum [OPTIONS] [DSN]
pt-table-checksum:在主<M>上通过执行校验的查询对复制的一致性进行检查,对比主从的校验值,从而产生结果。DSN指向的是主的地址,该工具的退出状态不为零,如果发现有任何差别,或者如果出现任何警告或错误,更多信息请见官网。
不指定任何参数,会直接对本地的所有数据库的表进行检查。
pt-table-checksum –S /tmp/mysqld.sock u=root,p=123456
注意:
1、根据测试,需要一个技能登录主库,也能登录从库,而且还能同步数据库的账号;
2、只能指定一个host,必须为主库的IP;
3、在检查时会向表加S锁;
4、运行之前需要从库的同步IO和SQL进程是YES状态。
执行检测(MASTER上):
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=test h=192.168.0.81,u=root,p=123 --empty-replicate-table --create-replicate-table
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
09-18T12:03:16 0 1 5 1 0 0.018 test.t1
参数说明:
TS :完成检查的时间。
ERRORS :检查时候发生错误和警告的数量。
DIFFS :0表示一致,1表示不一致。当指定--no-replicate-check时,会一直为0,当指定--replicate-check-only会显示不同的信息。
ROWS :表的行数。
CHUNKS :被划分到表中的块的数目。
SKIPPED :由于错误或警告或过大,则跳过块的数目。
TIME :执行的时间。
TABLE :被检查的表名。
参数意义:
--nocheck-replication-filters :不检查复制过滤器,建议启用。后面可以用--databases来指定需要检查的数据库。
--no-check-binlog-format : 不检查复制的binlog模式,要是binlog模式是ROW,则会报错。
--replicate-check-only :只显示不同步的信息。
--replicate= :把checksum的信息写入到指定表中,建议直接写到被检查的数据库当中。
--databases= :指定需要被检查的数据库,多个则用逗号隔开。
--tables= :指定需要被检查的表,多个用逗号隔开
h=127.0.0.1 :Master的地址
u=root :用户名
p=123456 :密码
P=3306 :端口
参数解释:
# --h -u -p -P -S -d 连接信息
# --nocheck-replication-filters 检测中忽略mysql 配置参数binlog_ignore_db等
# --nocheck-binlog-format 不检测日志格式
# --replicate 指定checksum 存储的db和表, 如:pt.checksum
# --databases 指定数据库,如:nobserver_new
# --chunk-size, --chunk-size-limit 用于指定检测块的大小,可控性更强
# --ignore-databases/tables/column 跳出指定元素的过滤
# --lock-wait-timeout innodb 锁的超时设定, 默认为1
# --max-load 设置最大并发连接数
# --replicate-check-only 只输出数据不一致的信息
更多的参数请见官网,上面指出来的是常用的,对该场景够用的参数。通过DIFFS是1可以看出主从的表数据不一致,通过查看从库上的test.checksum表可以看到主从库的检验信息。当DIFFS列全部为0时表示Master、Slave无差异。
mysql> select * from checksum\G;
*************************** 1. row ***************************
db: test
tbl: t1
chunk: 1
chunk_time: 0.001604
chunk_index: NULL
lower_boundary: NULL
upper_boundary: NULL
this_crc: 13fa7d9d #从的校验值
this_cnt: 4 #从的行数
master_crc: aa7a56c3 #主的校验值
master_cnt: 5 #主的行数
ts: 2013-09-18 12:03:16
1 row in set (0.00 sec)
通过上面的 this_crc <> master_crc 更能清楚的看出他们的不一致了,通过chunk知道是这个张表的哪个块上的记录出现不一致。要是主的binlog模式是Row 则会报错:
Replica db2 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.
从错误信息得出,要是不改binlog模式的话,则在执行上面的命令时候要指定:--no-check-binlog-format,即:
pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate-check-only --replicate=test.checksum --databases=test --tables=t1 h=127.0.0.1,u=root,p=123,P=3306
指定--replicate-check-only参数会在前一次pt-table-checksum检验的数据之上比较(不会再执行计算),显示出数据不一致的SLAVE主机名:
# pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate-check-only --replicate=test.checksum --databases=test --tables=t1 h=127.0.0.1,u=root,p=123456,P=3306
# pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=test h=192.168.0.81,u=root,p=123 --empty-replicate-table --create-replicate-table --replicate-check-only
Differences on host122
TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY
test.t1 1 -1 1
数据不一致的SLAVE和表都找出来了,下面就用pt-table-sync来修补数据。
执行如下sql语句返回若为空,则说明修复成功:
SELECT * FROM test.checksums
WHERE
master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);
如果从机使用了不同的端口,则需要用如下的方法来做:
Master指定Slave信息
--test库中创建dsns表
mysql> use test
mysql> CREATE TABLE `dsns` ( `id` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) DEFAULT NULL, `dsn` varchar(255) NOT NULL, PRIMARY KEY (`id`) );
--指定slave信息(如果有多个slave,就插入多条slave信息)
mysql> INSERT INTO dsns (parent_id,dsn) values(1,'h=123.59.7.109,u=checksums,p=123456,P=3307');
mysql> exit
注:如果主从端口不同,执行pt-table-checksum命令时多加 --recursion-method=dsn=h=123.59.7.118,D=test,t=dsns 参数即可。如果主从端口相同都是3306端口,--recursion-method=dsn=h=123.59.7.118,D=test,t=dsns参数省略即可。
pt-table-sync修复从库不一致的数据
使用方法:
pt-table-sync [OPTIONS] DSN [DSN]
pt-table-sync: 高效的同步MySQL表之间的数据,它可以做单向和双向同步的表数据。可以同步单个表,也可以同步整个库。它不同步表结构、索引、或任何其他模式对象。所以在修复一致性之前需要保证它们表存在。
继续上面的复制环境,主和从的t1表数据不一致,需要修复。
执行:
[root@freeoa ~]# pt-table-sync --print --replicate=test.checksum h=192.168.0.81,u=root,p=123,P=3306 h=192.168.0.83,u=root,p=123,P=3306
#先MASTER的IP,再SLAVE的IP
REPLACE INTO `test`.`t1`(`id`, `name`) VALUES ('5', 'ee')
/*percona-toolkit src_db:test src_tbl:t1 src_dsn:P=3306,h=192.168.0.81,p=...,u=root dst_db:test dst_tbl:t1 dst_dsn:P=3306,h=192.168.0.83,p=...,u=root lock:1 transaction:1 changing_src:test.checksum replicate:test.checksum bidirectional:0 pid:24763 user:root host:freeoa*/;
参数的意义:
--replicate= :指定通过pt-table-checksum得到的表,这2个工具差不多都会一直用。
--databases= : 指定执行同步的数据库,多个用逗号隔开。
--tables= :指定执行同步的表,多个用逗号隔开。
--sync-to-master :指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。
h=127.0.0.1 :服务器地址,命令里有2个ip,第一次出现的是M的地址,第2次是Slave的地址。
u=root :帐号。
p=123456 :密码。
--print :打印,但不执行命令。
--execute :执行命令。
更多的参数请见官网,上面指出来的是常用的,对该场景够用的参数。
和上面的命令一样效果的命令:
[root@freeoa ~]# pt-table-sync --print --sync-to-master h=192.168.0.83,u=root,p=123,P=3306 --databases test --tables t1
#用一个IP (SLAVE)就可以了。
REPLACE INTO `test`.`t1`(`id`, `name`) VALUES ('5', 'ee') /*percona-toolkit src_db:test src_tbl:t1 src_dsn:P=3306,h=192.168.0.81,p=...,u=root dst_db:test dst_tbl:t1 dst_dsn:P=3306,h=192.168.0.83,p=...,u=root lock:1 transaction:1 changing_src:1 replicate:0 bidirectional:0 pid:24798 user:root host:freeoa*/;
还可以让它自己执行修复数据的SQL语句,但是这样就没有输出了:
[root@freeoa ~]# pt-table-sync --execute --sync-to-master h=192.168.0.83,u=root,p=123,P=3306 --databases test --tables t1
建议还是用--print 打印出来的好,这样就可以知道那些数据有问题,可以人为的干预下。不然直接执行了,出现问题之后更不好处理。总之还是在处理之前做好数据的备份工作。
注意:要是表中没有唯一索引或则主键则会报错:
Can't make changes on the master because no unique index exists at /usr/local/bin/pt-table-sync line 10591.
补充:
要是从库有的数据,而主库没有,那这个数据怎么处理?会给出删除SLAVE多余数据,和修复SLAVE缺失数据的SQL语句。
该工具执行检查表动作,检查连接的帐号需要有很高的权限,在一般权限上需要加SELECT, PROCESS, SUPER, REPLICATION SLAVE等权限。pt-table-checksm 配合pt-table-sync使用,在执行pt-table-sync数据同步之前,一定要执行pt-table-checksm命令检查。
脚本在那里执行(都是在主库服务器,从库只是检查下结果)
GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE
检查主库,发现出现一样的情况,中文“员工”变成了“??”,猜想和字符集设置相关。于是检查数据库字符集设置,发现test库字符集非utf8。
重新执行以上述上面的步骤,发现一切正常!关键第4步要加–charset=utf8参数
# pt-table-sync --execute --replicate test.checksums --charset=utf8 --sync-to-master h=192.168.1.207,P=3306,u=root,p=123456
要是有中文的则需要加上:--charset=utf8,防止乱码,这个笔者有血的教训。该工具检查的表,需要检查连接的帐号需要有很高的权限,在一般权限行需要加SELECT, PROCESS, SUPER, REPLICATION SLAVE等权限,测试方便我直接给了ALL的权限,pt-table-checksum 和 pt-table-sync 一起互补使用,检查一定是在同步操作之前定要有备份。
其它一些可用的pt工具集
pt-config-diff
功能介绍:
比较mysql配置文件和服务器参数
用法介绍:
pt-config-diff [OPTION...] CONFIG CONFIG [CONFIG...]
CONFIG可以是文件也可以是数据源名称,最少必须指定两个配置文件源,就像unix下面的diff命令一样,如果配置完全一样就不会输出任何东西。
范例1:查看本地和远程服务器的配置文件差异:
pt-config-diff h=localhost h=192.168.3.92 --user=root --password=paswd
范例2:比较本地配置文件和远程服务器的差异:
pt-config-diff /etc/my.cnf h=192.168.3.92 --user=root --password=paswd
范例3:比较本地两个配置文件的差异:
pt-config-diff /usr/local/mysql/share/mysql/my-large.cnf /usr/local/mysql/share/mysql/my-medium.cnf
pt-mysql-summary
功能介绍:
精细地对mysql的配置和sataus信息进行汇总,汇总后你直接看一眼就能看明白。
用法介绍:
pt-mysql-summary [OPTIONS] [-- MYSQL OPTIONS]
工作原理:连接mysql后查询出status和配置信息保存到临时目录中,然后用awk和其他的脚本工具进行格式化。OPTIONS可以查阅官网的相关页面。
范例1:汇总本地mysql服务器的status和配置信息:
pt-mysql-summary -- --user=root --password=paswd --host=localhost
范例2:汇总本地mysql服务器192.168.0.92的status和配置信息:
pt-mysql-summary -- --user=root --password=paswd --host=192.168.0.92
pt-variable-advisor
功能介绍:
分析mysql的参数变量,并对可能存在的问题提出建议
用法介绍:
pt-variable-advisor [OPTION...] [DSN]
原理:根据预先定义的规则检查show variables中的配置错误的设置和值。
范例1:从localhost获取变量值
pt-variable-advisor --user=root --password=paswd localhost
范例2:从指定的文件中读取配置,这个有格式要求
pt-variable-advisor --user=root --password=paswd --source-of-variables my.cnf
安装相关的Perl依赖:
yum install perl-DBI perl-DBD-MySQL perl-TermReadKey perl-Time-HiRes perl-IO-Socket-SSL -y
先介绍一些关于二进制日志的知识
mysql binlog日志有三种格式,分别为Statement, Mixed,以及ROW。
1.Statement
每一条会修改数据的sql都会记录在binlog中。
优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。(相比row能节约多少性能与日志量,这个取决于应用的SQL情况,正常同一条记录修改或者插入row格式所产生的日志量还小于Statement产生的日志量,但是考虑到如果带条件的update操作,以及整表删除,alter表等操作,ROW格式会产生大量日志,因此在考虑是否使用ROW格式日志时应该跟据应用的实际情况,其所产生的日志量会增加多少,以及带来的IO性能问题。)
缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同 的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题(如sleep()函数, last_insert_id(),以及user-defined functions(udf)会出现问题).
2.Row
不记录sql语句上下文相关信息,仅保存哪条记录被修改。
优点:binlog中可以不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以rowlevel的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题
缺点:所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比如一条update语句,修改多条记录,则binlog中每一条修改都会有记录,这样造成binlog日志量会很大,特别是当执行alter table之类的语句的时候,由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中。
3.Mixed
是以上两种level的混合使用,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种.新版本的MySQL中队row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录。至于update或者delete等修改数据的语句,还是会记录所有行的变更。
pt-table-checksum在MASTER上校验指定库、表,将结果存在一个库表里,复制进程将检验sql传递到slave上再执行一次。通过比较主从的检验值确定数据是否一致。利用主从复制做检验,不需要在检验期间对主从数据库同时锁表,可以控制校验的数据和速度,不影响到正常服务。它通过在主库执行基于statement的sql语句来生成主库数据块的checksum,把相同的sql语句传递到从库,并在从库上计算相同数据块的checksum,最后比较主从库上相同数据块的checksum值,由此判断主从数据是否一致。这种校验是分表进行的,在每个表内部又是分块进行的,而且pt工具本身提供了非常多的限流选项,因此对线上服务的冲击较小。
在从机上制造相差数据
update content set hits=ceil(rand()*100) where id>=3060;
on master(0.81)
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=freeoa --tables=content h=192.168.0.83,u=dba,p=yourpaswd --empty-replicate-table --create-replicate-table
Failed to SET SESSION innodb_lock_wait_timeout=1: DBD::mysql::db do failed: Variable 'innodb_lock_wait_timeout' is a read only variable [for Statement "SET SESSION innodb_lock_wait_timeout=1"] at /usr/bin/pt-table-checksum line 6450.
The current innodb_lock_wait_timeout value 50 is greater than the --lock-wait-timeout value 1 and the variable cannot be changed. innodb_lock_wait_timeout is only dynamic when using the InnoDB plugin. To prevent this warning, either specify --lock-wait-time=50, or manually set innodb_lock_wait_timeout to a value less than or equal to 1 and restart MySQL.
You do not have the PROCESS privilege at /usr/bin/pt-table-checksum line 2759.
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=freeoa --tables=content h=192.168.0.83,u=dba,p=yourpaswd --empty-replicate-table --create-replicate-table --lock-wait-time=50
You do not have the PROCESS privilege at /usr/bin/pt-table-checksum line 2759.
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=freeoa --tables=content h=192.168.0.83,u=dba,p=yourpaswd --empty-replicate-table --create-replicate-table --lock-wait-time=50
=>
pt-table-checksum --nocheck-replication-filters --replicate=freeoa.checksum --databases=freeoa --tables=content u=root,p=1qaz2wsx,S=/tmp/mysql51.sock --empty-replicate-table --create-replicate-table --lock-wait-time=50
在从机上(0.83)
pt-table-sync --execute --replicate test.checksums --sync-to-master h=192.168.0.80,P=3306,u=dba,p=yourpaswd
pt-table-sync --print --execute --verbose --replicate freeoa.checksum --sync-to-master h=192.168.0.80,P=3306,u=dba,p=yourpaswd
登录从库执行:
SELECT * FROM freeoa.checksum WHERE master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);
返回若为空,则说明修复成功
=wzm表,记录数量:10000000
主机:
pt-table-checksum --nocheck-replication-filters --replicate=freeoa.checksum --databases=freeoa --tables=wzm u=root,p=1qaz2wsx,S=/tmp/mysql51.sock --empty-replicate-table --create-replicate-table --lock-wait-time=50
vbox虚拟机上1.7G的文件用时41s。
从机:
制造差异
update wzm set views=ceil(rand()*100) where cid between 328000000 and 328000900 and views<10;
开始重新同步:
pt-table-sync --print --execute --verbose --replicate freeoa.checksum --sync-to-master h=192.168.0.80,P=3306,u=dba,p=yourpaswd
pt-table-checksum --nocheck-replication-filters --replicate=newsclient_demo.checksum --databases=newsclient_demo u=dba,p=dbapasword,h=192.168.20.101,P=5113 --empty-replicate-table --create-replicate-table
do sql:
SELECT * FROM checksum WHERE master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);
SELECT * FROM test.checksum WHERE master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);
pt-table-checksum --nocheck-replication-filters --replicate=my_beta.checksum --databases=ym_beta u=dba,p=dbapasword,S=/tmp/mysql.sock --empty-replicate-table --create-replicate-table
为主从不同端口而设定:
CREATE TABLE `dsns` ( `id` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) DEFAULT NULL, `dsn` varchar(255) NOT NULL, PRIMARY KEY (`id`) );
--指定slave信息(如果有多个slave,就插入多条slave信息)
INSERT INTO dsns (parent_id,dsn) values(1,'h=192.168.20.114,u=dba,p=dbapasword,P=5133');
INSERT INTO dsns (parent_id,dsn) values(1,'h=192.168.20.182,u=dba,p=dbapasword,P=5133');
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum u=dba,p=dbapasword,S=/tmp/mysql.sock --empty-replicate-table --create-replicate-table --recursion-method=dsn=h=192.168.20.106,D=test,t=dsns --set-vars innodb_lock_wait_timeout=50 --databases=yqt
在从机上执行:
pt-table-sync --execute --verbose --replicate test.checksum --sync-to-master h=192.168.20.114,P=5133,u=dba,p=dbapasword --database=yqt
---------------------------------------------------------------
pt-table-checksum检查主从库数据的一致性
使用方法:
pt-table-checksum [OPTIONS] [DSN]
pt-table-checksum:在主<M>上通过执行校验的查询对复制的一致性进行检查,对比主从的校验值,从而产生结果。DSN指向的是主的地址,该工具的退出状态不为零,如果发现有任何差别,或者如果出现任何警告或错误,更多信息请见官网。
不指定任何参数,会直接对本地的所有数据库的表进行检查。
pt-table-checksum –S /tmp/mysqld.sock u=root,p=123456
注意:
1、根据测试,需要一个技能登录主库,也能登录从库,而且还能同步数据库的账号;
2、只能指定一个host,必须为主库的IP;
3、在检查时会向表加S锁;
4、运行之前需要从库的同步IO和SQL进程是YES状态。
执行检测(MASTER上):
pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=test h=192.168.0.81,u=root,p=123 --empty-replicate-table --create-replicate-table
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
09-18T12:03:16 0 1 5 1 0 0.018 test.t1
参数说明:
TS :完成检查的时间。
ERRORS :检查时候发生错误和警告的数量。
DIFFS :0表示一致,1表示不一致。当指定--no-replicate-check时,会一直为0,当指定--replicate-check-only会显示不同的信息。
ROWS :表的行数。
CHUNKS :被划分到表中的块的数目。
SKIPPED :由于错误或警告或过大,则跳过块的数目。
TIME :执行的时间。
TABLE :被检查的表名。
参数意义:
--nocheck-replication-filters :不检查复制过滤器,建议启用。后面可以用--databases来指定需要检查的数据库。
--no-check-binlog-format : 不检查复制的binlog模式,要是binlog模式是ROW,则会报错。
--replicate-check-only :只显示不同步的信息。
--replicate= :把checksum的信息写入到指定表中,建议直接写到被检查的数据库当中。
--databases= :指定需要被检查的数据库,多个则用逗号隔开。
--tables= :指定需要被检查的表,多个用逗号隔开
h=127.0.0.1 :Master的地址
u=root :用户名
p=123456 :密码
P=3306 :端口
参数解释:
# --h -u -p -P -S -d 连接信息
# --nocheck-replication-filters 检测中忽略mysql 配置参数binlog_ignore_db等
# --nocheck-binlog-format 不检测日志格式
# --replicate 指定checksum 存储的db和表, 如:pt.checksum
# --databases 指定数据库,如:nobserver_new
# --chunk-size, --chunk-size-limit 用于指定检测块的大小,可控性更强
# --ignore-databases/tables/column 跳出指定元素的过滤
# --lock-wait-timeout innodb 锁的超时设定, 默认为1
# --max-load 设置最大并发连接数
# --replicate-check-only 只输出数据不一致的信息
更多的参数请见官网,上面指出来的是常用的,对该场景够用的参数。通过DIFFS是1可以看出主从的表数据不一致,通过查看从库上的test.checksum表可以看到主从库的检验信息。当DIFFS列全部为0时表示Master、Slave无差异。
mysql> select * from checksum\G;
*************************** 1. row ***************************
db: test
tbl: t1
chunk: 1
chunk_time: 0.001604
chunk_index: NULL
lower_boundary: NULL
upper_boundary: NULL
this_crc: 13fa7d9d #从的校验值
this_cnt: 4 #从的行数
master_crc: aa7a56c3 #主的校验值
master_cnt: 5 #主的行数
ts: 2013-09-18 12:03:16
1 row in set (0.00 sec)
通过上面的 this_crc <> master_crc 更能清楚的看出他们的不一致了,通过chunk知道是这个张表的哪个块上的记录出现不一致。要是主的binlog模式是Row 则会报错:
Replica db2 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.
从错误信息得出,要是不改binlog模式的话,则在执行上面的命令时候要指定:--no-check-binlog-format,即:
pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate-check-only --replicate=test.checksum --databases=test --tables=t1 h=127.0.0.1,u=root,p=123,P=3306
指定--replicate-check-only参数会在前一次pt-table-checksum检验的数据之上比较(不会再执行计算),显示出数据不一致的SLAVE主机名:
# pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate-check-only --replicate=test.checksum --databases=test --tables=t1 h=127.0.0.1,u=root,p=123456,P=3306
# pt-table-checksum --nocheck-replication-filters --replicate=test.checksum --databases=test h=192.168.0.81,u=root,p=123 --empty-replicate-table --create-replicate-table --replicate-check-only
Differences on host122
TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY
test.t1 1 -1 1
数据不一致的SLAVE和表都找出来了,下面就用pt-table-sync来修补数据。
执行如下sql语句返回若为空,则说明修复成功:
SELECT * FROM test.checksums
WHERE
master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);
如果从机使用了不同的端口,则需要用如下的方法来做:
Master指定Slave信息
--test库中创建dsns表
mysql> use test
mysql> CREATE TABLE `dsns` ( `id` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) DEFAULT NULL, `dsn` varchar(255) NOT NULL, PRIMARY KEY (`id`) );
--指定slave信息(如果有多个slave,就插入多条slave信息)
mysql> INSERT INTO dsns (parent_id,dsn) values(1,'h=123.59.7.109,u=checksums,p=123456,P=3307');
mysql> exit
注:如果主从端口不同,执行pt-table-checksum命令时多加 --recursion-method=dsn=h=123.59.7.118,D=test,t=dsns 参数即可。如果主从端口相同都是3306端口,--recursion-method=dsn=h=123.59.7.118,D=test,t=dsns参数省略即可。
pt-table-sync修复从库不一致的数据
使用方法:
pt-table-sync [OPTIONS] DSN [DSN]
pt-table-sync: 高效的同步MySQL表之间的数据,它可以做单向和双向同步的表数据。可以同步单个表,也可以同步整个库。它不同步表结构、索引、或任何其他模式对象。所以在修复一致性之前需要保证它们表存在。
继续上面的复制环境,主和从的t1表数据不一致,需要修复。
执行:
[root@freeoa ~]# pt-table-sync --print --replicate=test.checksum h=192.168.0.81,u=root,p=123,P=3306 h=192.168.0.83,u=root,p=123,P=3306
#先MASTER的IP,再SLAVE的IP
REPLACE INTO `test`.`t1`(`id`, `name`) VALUES ('5', 'ee')
/*percona-toolkit src_db:test src_tbl:t1 src_dsn:P=3306,h=192.168.0.81,p=...,u=root dst_db:test dst_tbl:t1 dst_dsn:P=3306,h=192.168.0.83,p=...,u=root lock:1 transaction:1 changing_src:test.checksum replicate:test.checksum bidirectional:0 pid:24763 user:root host:freeoa*/;
参数的意义:
--replicate= :指定通过pt-table-checksum得到的表,这2个工具差不多都会一直用。
--databases= : 指定执行同步的数据库,多个用逗号隔开。
--tables= :指定执行同步的表,多个用逗号隔开。
--sync-to-master :指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。
h=127.0.0.1 :服务器地址,命令里有2个ip,第一次出现的是M的地址,第2次是Slave的地址。
u=root :帐号。
p=123456 :密码。
--print :打印,但不执行命令。
--execute :执行命令。
更多的参数请见官网,上面指出来的是常用的,对该场景够用的参数。
和上面的命令一样效果的命令:
[root@freeoa ~]# pt-table-sync --print --sync-to-master h=192.168.0.83,u=root,p=123,P=3306 --databases test --tables t1
#用一个IP (SLAVE)就可以了。
REPLACE INTO `test`.`t1`(`id`, `name`) VALUES ('5', 'ee') /*percona-toolkit src_db:test src_tbl:t1 src_dsn:P=3306,h=192.168.0.81,p=...,u=root dst_db:test dst_tbl:t1 dst_dsn:P=3306,h=192.168.0.83,p=...,u=root lock:1 transaction:1 changing_src:1 replicate:0 bidirectional:0 pid:24798 user:root host:freeoa*/;
还可以让它自己执行修复数据的SQL语句,但是这样就没有输出了:
[root@freeoa ~]# pt-table-sync --execute --sync-to-master h=192.168.0.83,u=root,p=123,P=3306 --databases test --tables t1
建议还是用--print 打印出来的好,这样就可以知道那些数据有问题,可以人为的干预下。不然直接执行了,出现问题之后更不好处理。总之还是在处理之前做好数据的备份工作。
注意:要是表中没有唯一索引或则主键则会报错:
Can't make changes on the master because no unique index exists at /usr/local/bin/pt-table-sync line 10591.
补充:
要是从库有的数据,而主库没有,那这个数据怎么处理?会给出删除SLAVE多余数据,和修复SLAVE缺失数据的SQL语句。
该工具执行检查表动作,检查连接的帐号需要有很高的权限,在一般权限上需要加SELECT, PROCESS, SUPER, REPLICATION SLAVE等权限。pt-table-checksm 配合pt-table-sync使用,在执行pt-table-sync数据同步之前,一定要执行pt-table-checksm命令检查。
脚本在那里执行(都是在主库服务器,从库只是检查下结果)
GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE
检查主库,发现出现一样的情况,中文“员工”变成了“??”,猜想和字符集设置相关。于是检查数据库字符集设置,发现test库字符集非utf8。
重新执行以上述上面的步骤,发现一切正常!关键第4步要加–charset=utf8参数
# pt-table-sync --execute --replicate test.checksums --charset=utf8 --sync-to-master h=192.168.1.207,P=3306,u=root,p=123456
要是有中文的则需要加上:--charset=utf8,防止乱码,这个笔者有血的教训。该工具检查的表,需要检查连接的帐号需要有很高的权限,在一般权限行需要加SELECT, PROCESS, SUPER, REPLICATION SLAVE等权限,测试方便我直接给了ALL的权限,pt-table-checksum 和 pt-table-sync 一起互补使用,检查一定是在同步操作之前定要有备份。
其它一些可用的pt工具集
pt-config-diff
功能介绍:
比较mysql配置文件和服务器参数
用法介绍:
pt-config-diff [OPTION...] CONFIG CONFIG [CONFIG...]
CONFIG可以是文件也可以是数据源名称,最少必须指定两个配置文件源,就像unix下面的diff命令一样,如果配置完全一样就不会输出任何东西。
范例1:查看本地和远程服务器的配置文件差异:
pt-config-diff h=localhost h=192.168.3.92 --user=root --password=paswd
范例2:比较本地配置文件和远程服务器的差异:
pt-config-diff /etc/my.cnf h=192.168.3.92 --user=root --password=paswd
范例3:比较本地两个配置文件的差异:
pt-config-diff /usr/local/mysql/share/mysql/my-large.cnf /usr/local/mysql/share/mysql/my-medium.cnf
pt-mysql-summary
功能介绍:
精细地对mysql的配置和sataus信息进行汇总,汇总后你直接看一眼就能看明白。
用法介绍:
pt-mysql-summary [OPTIONS] [-- MYSQL OPTIONS]
工作原理:连接mysql后查询出status和配置信息保存到临时目录中,然后用awk和其他的脚本工具进行格式化。OPTIONS可以查阅官网的相关页面。
范例1:汇总本地mysql服务器的status和配置信息:
pt-mysql-summary -- --user=root --password=paswd --host=localhost
范例2:汇总本地mysql服务器192.168.0.92的status和配置信息:
pt-mysql-summary -- --user=root --password=paswd --host=192.168.0.92
pt-variable-advisor
功能介绍:
分析mysql的参数变量,并对可能存在的问题提出建议
用法介绍:
pt-variable-advisor [OPTION...] [DSN]
原理:根据预先定义的规则检查show variables中的配置错误的设置和值。
范例1:从localhost获取变量值
pt-variable-advisor --user=root --password=paswd localhost
范例2:从指定的文件中读取配置,这个有格式要求
pt-variable-advisor --user=root --password=paswd --source-of-variables my.cnf