两台MySQL,发生了种种种种,导致了两个表的数据不一致,但是同步还在正常进行,后来意识到这种问题(可能之前skip啊,或者一开始搭建的时候就是不一致的状态),该如何修复呢?
如果数据量小的情况可以考虑从新导数据,如果数据量很大的话,那就太要命了
于是可以用percona-toolkit这个工具修复并并检查这种情况的
再主备同步的时候在进行如下操作:
在主库上安装pt-table-checksum
安装:

1.安装软件包:
# yum install perl perl-devel perl-Time-HiRes perl-DBI perl-DBD-MySQL
2.安装工具percona-toolkit
  # yum install http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm
# yum list | grep percona-toolkit

# yum install percona-toolkit

3.安装pt-table-checksum
 # wget http://www.percona.com/get/percona-toolkit.tar.gz

4.解压并安装
# tar zxvf percona-toolkit.tar.gz
# cd percona-toolkit-3.0.13
# perl Makefile.PL
#   make && make install
安装完成后:
# pt-table-checksum
# pt-table-sync 检查安装是否成功

mysql(五)------针对主从同步的情况两个库进行数据校对及恢复

如果报:
erl: relocation error: /usr/lib64/perl5/vendor_perl/auto/DBD/mysql/mysql.so
如有报错:
DBD::mysql::db do failed: Access denied; you need (at least one of) the SUPER privilege(s) for this operation [for Statement "/*!50105 SET @@binlog_format="STATEMENT"*/"] at /usr/local/bin/mk-table-sync line 8568.
Issuing rollback() due to DESTROY without explicit disconnect() of DBD::mysql::db handle ;host=192.168.1.101;port=3306;mysql_read_default_group=client at /usr/local/bin/mk-table-sync line 8568.
解决办法:安装DBI和DBD-MySQL
下载地址:
http://ftp.cuhk.edu.hk/pub/packages/perl/CPAN/authors/id/T/TI/TIMB/
http://search.cpan.org/dist/DBD-mysql/ 
或者百度云盘下载:https://pan.baidu.com/s/1miv0S8g (提取密码:fh24)
[root@master-server src]# tar -zvxf DBI-1.634.tar.gz 
[root@master-server src]# cd DBI-1.634
[root@master-server DBI-1.634]# perl Makefile.PL
[root@master-server DBI-1.634]# make && make install
[root@master-server src]# tar -zvxf DBD-mysql-4.041_01.tar.gz 
[root@master-server src]# cd DBD-mysql-4.041_01
[root@master-server DBD-mysql-4.041_01]# perl Makefile.PL --mysql_config=/usr/local/mysql/bin/mysql_config         //主库mysql安装路径/usr/local/mysql
[root@master-server DBD-mysql-4.041_01]# make
[root@master-server DBD-mysql-4.041_01]# make install

5.在主数据库master上建立用户并授权
    CREATE USER 'test' IDENTIFIED BY "test";
    grant all privileges on *.* to 'test' identified by 'test';
    flush privileges;

mysql(五)------针对主从同步的情况两个库进行数据校对及恢复_第1张图片

6.检测下test是否可以登录

7.但是我们检查使用的mysql用户一般是没有 create table 权限的,所以你可能需要先手动创建:
CREATE DATABASE IF NOT EXISTS percona;CREATE TABLE IF NOT EXISTS percona.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;

8.生产环境中数据库用户权限一般都是有严格管理的,假如连接用户是repl_user(即直接用复制用户来检查),它应该额外赋予对其它库的 SELECT ,LOCK TABLES 权限,如果后续要用 pt-table-sync 就就需要写权限了。对percona库有写权限:
   GRANT ALL PRIVILEGEES on percona.* to repl_user@'%' IDENTIFIED BY 'repl_pass';
    GRANT SELECT,LOCK TABLES,PROCESS,SUPER on *.* to repl_user@'%';

注:
a.为了减少不必要的麻烦,确保你的 repl_user@'xxx' 用户能同时登陆主库和从库
b.--create-replicate-table 选项会自动创建 percona.checksums 表,但也意味着赋予额外的 CREATE TABLE权限给 percona_tk@'xxx' 用户。默认yes
c.PROCESS用于自动发现从库信息,SUPER权限用于set binlog_format。
d.--no-check-replication-filters 表示不需要检查 Master 配置里是否指定了 Filter。 默认会检查,如果配置了 Filter,如      replicate_do_db,replicate-wild-ignore-table,binlog_ignore_db 等,在从库checksum就与遇到表不存在而报错退出,所以官方默认是yes(--check-replication-filters)但我们实际在检测中时指定--databases=,所以就不存在这个问题,干脆不检测
e.--empty-replicate-table:每个表checksum开始前,清空它之前的检测数据(不影响其它表的checksum数据),默认yes。当然如果使用--resume启动检测数据不会清空。
当启用--noempty-replicate-table即不清空时,不计算计算chunk,只计算。
f.--databases=,-d:要检查的数据库,逗号分隔。用脚趾头想也知道 --databases-regex 正则匹配要检测的数据库,--ignore-databases[-regex]忽略检查的库。Filter选项。
g.--tables=,-t:要检查的表,逗号分隔。如果要检查的表分布在不同的db中,可以用--tables=dbname1.table1,dbnamd2.table2的形式。同理有--tables-regex,--ignore-tables,--ignore-tables-regex。--replicate指定的checksum表始终会被过滤。
h.--recursion-method:发现从库的方式。pt-table-checksum 默认可以在主库的 processlist中找到从库复制进程,从而识别出有哪些从库,但如果使用是非标准3306端口,会导致找不到从库信息。此时就会自动采用host方式,但需要提前在从库 my.cnf 里面配置report_host、report_port信息,如:
    report_host = MASTER_HOSt report_port = 1330
最终极的办法是dsn,dsn指定的是某个表(如 percona.dsns ),表行记录是改主库的(多个)从库的连接信息。适用以下任一情形:
主库不能自动发现从库
不想在从库添加额外配置(因为要重启)
主从检测连接用户信息不一样
多个从库时只想验证指定从库的一致
我比较倾向使用DSN的方式。这个dsns表只需要在执行 pt-table-checksum 命令的服务器上能够访问到就行。这里纠正一个认识,网上很多人说 pt-table-checksum 要在主库上执行,其实不是的,我的mysql实例比较多,只需在某一台服务器上安装percona-toolkit,这台服务能够同时访问主库和从库就行了。具体用法见后面实例。

9.

pt-table-checksum注意事项:
a.  根据测试,需要一个即能登录主库,也能登录从库的账号;
b.  只能指定一个host,必须为主库的IP;
c.  在检查时会向表加S锁;
d.如果master和slave的binlog日志不是STATEMENT格式,要用--no-check-binlog-format选项
e.  运行之前需要从库的同步IO和SQL进程是YES状态。
f. 表要有主键索引或唯一键索引

10.安装完成测试:

11.在主库上(master:3306),如下:
   Select * from t1.student;

mysql(五)------针对主从同步的情况两个库进行数据校对及恢复_第2张图片

12.在从库上(slave:3306),如下:
Select * from t1.student;

mysql(五)------针对主从同步的情况两个库进行数据校对及恢复_第3张图片

校验:
pt-table-checksum h=10.1.31.78,u=test,p='test',P=3306 --databases=t1   --nocheck-replication-filters --no-check-binlog-format

mysql(五)------针对主从同步的情况两个库进行数据校对及恢复

TS :完成检查的时间。
ERRORS :检查时候发生错误和警告的数量。
DIFFS :0表示一致,1表示不一致。当指定--no-replicate-check时,会一直为0,当指定--replicate-check-only会显示不同的信息。
ROWS :表的行数。
CHUNKS :被划分到表中的块的数目。
SKIPPED :由于错误或警告或过大,则跳过块的数目。
TIME :执行的时间。
TABLE :被检查的表名。
常见错误
h.Diffs cannot be detected because no slaves were found
不能自动找到从库,确认processlist或host或dsns方式用对了。
i.Cannot connect to h=slave1.*.com,p=...,u=percona_user
可以在pt-table-checksum命令前加PTDEBUG=1来看详细的执行过程,如端口、用户名、权限错误。
j.Waiting for the --replicate table to replicate to XXX
问题出在 percona.checksums 表在从库不存在,根本原因是没有从主库同步过来,所以看一下从库是否延迟严重。
k.Pausing because Threads_running=25
反复打印出类似上面停止检查的信息。这是因为当前数据库正在运行的线程数大于默认25,pt-table-checksum 为了减少对库的压力暂停检查了。等数据库压力过了就好了,或者也可以直接 Ctrl+C 终端,下一次加上--resume继续执行,或者加大--max-load=值。
l.字符集问题
Error checksumming table Error executing checksum query: DBD::mysql::st execute failed: Illegal mix of collations
12-17T14:48:04 Error checksumming table d_ec_cs.t_online_cs: Error executing checksum query: 
DBD::mysql::st execute failed: Illegal mix of collations for operation 'concat_ws' [for Statement "REPLACE INTO `percona`.`ali_checksum` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT ?, ?, ?, ?, ?, ?, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `f_cs_id`, `f_corp_id`, `f_valid`, `f_show_name`, `f_online_msg`, `f_offline_msg`, `f_show_mobile`, `f_group_id`, `f_qq`, `f_show_qq`, `f_msn`, `f_show_msn`, `f_sms_online`, `f_scheme`, `f_tel`, `f_telno`, `f_show_tel`, `f_contact`, `f_mobile`, `f_position`, `f_other1`, `f_other2`, `f_other_text1`, `f_other_text2`, `f_email`, `f_qq_first`, `f_qq_first_type`, `f_aids_open`, `f_aids_qq`, `f_aids_crmqq`, `f_aids_yahoo`, `f_aids_skype`, `f_aids_aliww`, `f_aids_msn`, `f_aids_alibaba`, `f_aids_alitrade`, CONCAT(ISNULL(`f_show_name`), ISNULL(`f_group_id`), ISNULL(`f_qq`), ISNULL(`f_show_qq`), ISNULL(`f_sms_online`), ISNULL(`f_other_text1`), ISNULL(`f_other_text2`), ISNULL(`f_email`)) )) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `d_ec_cs`.`t_online_cs` 
/*checksum table*/" with ParamValues: 0='d_ts_profile', 1='t_user_account', 2=1, 3=undef, 
没找到解决办法

备库插入几笔数据
mysql(五)------针对主从同步的情况两个库进行数据校对及恢复_第4张图片
mysql(五)------针对主从同步的情况两个库进行数据校对及恢复_第5张图片

再次校验:
 pt-table-checksum h=10.1.31.78,u=test,p='test',P=3306 --databases=t1   --nocheck-replication-filters --no-check-binlog-format

mysql(五)------针对主从同步的情况两个库进行数据校对及恢复

错10 ROWS

这时用pt-table-sync修复
i.自动消除差异(不推荐)
pt-table-sync --print --execute --sync-to-master h=10.1.31.77,P=3306,u=checksums,p='checksums' --databases=newtables --tables=tb1

ii.打印出sql语句,人工干预到Slave库执行(推荐)

pt-table-sync --print --sync-to-master h=10.1.31.77,P=3306,u=checksums,p='checksums' --databases=newtables --tables=tb1
或
pt-table-sync --print --sync-to-master h=10.1.31.77,P=3306,u=checksums,p='checksums'--replicate pt.checksums

#--sync-to-master : 指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。
#--replicate :指定通过pt-table-checksum得到的表,这2个工具差不多都会一直用。
#--print :打印,但不执行命令。
#--execute  :执行命令。

备注:Slave需要授权主库Drop 和Create Temporary Tables权限

8.检验
重新执行一次pt-table-checksum,查看是否还存在差异。

四、注意事项
1.采用replace into来修复主从不一致,必须保证被replace的表上有主键或唯一键,否则replace into退化成insert into,起不到修复的效果。这种情况下pt-table-sync会采用其他校验和修复算法,但是效率非常低,例如对所有列的group by然后求count(*)(表一定要有主键!)。
2.主从数据不一致需要通过replace into来修复,该sql语句必须是语句级。pt-table-sync会把它发起的所有sql语句都设置为statement格式,而不管全局的binlog_format值。这在级联A-B-C结构中,也会遇到pt-table-checksum曾经遇到的问题,引起行格式的中继库的从库卡库是必然。不过pt-table-sync默认会无限递归的对从库的binlog格式进行检查并警告。
3.由于pt-table-sync每次只能修复一个表,所以如果修复的是父表,则可能导致子表数据连带被修复,这可能会修复一个不一致而引入另一个不一致;如果表上有触发器,也可能遇到同样问题。所以在有触发器和主外键约束的情况下要慎用。pt-table-sync工具同样也不欢迎主从异构的结构。pt-table-sync工具默认会进行先决条件的检查。

4.pt-table-sync在修复过程中不能容忍从库延迟,这正好与pt-table-checksum相反。如果从库延迟太多,pt-table-sync会长期持有对chunk的for update锁,然后等待从库的master_pos_wait执行完毕或超时。从库延迟越大,等待过程就越长,主库加锁的时间就越长,对线上影响就越大。因此要严格设置max-lag。

5.对从库数据的修复通常是在主库执行sql来同步到从库。因此,在有多个从库时,修复某个从库的数据实际会把修复语句同步到所有从库。数据修复的代价取决于从库与主库不一致的程度,如果某从库数据与主库非常不一致,举例说,这个从库只有表结构,那么需要把主库的所有数据重新灌一遍,然后通过binlog同步,同时会传递到所有从库。这会给线上带来很大压力,甚至拖垮集群。正确的做法是,先用pt-table-checksum校验一遍,确定不一致的程度:如果不同步的很少,用pt-table-sync直接修复;否则,用备份先替换它,然后用pt-table-sync修复。 说明: 这实际提供了一种对myisam备份的思路:如果仅有一个myisam的主库,要为其增加从库,则可以:先mysqldump出表结构到从库上,然后启动同步,然后用pt-table-sync来修复数据。