问题起源:
- mysql数据库同步过程中经常会因为某种错误导致同步出错而暂停,此时使用
show slave statusG
命令能查看到错误数据此时Slave_SQL_Running: No
,为了解决这个问题一般使用如下命令解决
stop slave;
set global sql_slave_skip_counter =1;
start slave;
有时候忽略一次错误还不行,需要忽略很多,那么忽略错误过程中就会出现数据不一致的问题(有些正常数据被忽略了)
- 某个服务器异常宕机导致部分SQL未同步
如何解决:
为了保证不同mysql服务器之间的数据一致,可以采用如下的一个工具集合Percona-toolkit
他有2个工具:pt-table-checksum
和pt-table-sync
pt-table-checksum
:用于检测2个数据库之间哪些表的数据不一致
pt-table-sync
:用于修复数据不一致的表或者库
这里需要注意的地方是:必须选择一个库作为参考,强烈建议选择主库作为参考,主库和从库数据不一致时把主库的数据同步到从库达到一致。如果既要把主库的部分表同步到从库 又要想把从库的部分数据同步到主库(主主同步时会有此需求)则需要采取特殊手段,后面有说明
第一步:安装工具集Percona-toolkit
工具集请安装在主库的服务器上面
#安装依赖包
yum install perl perl-DBI perl-DBD-MySQL perl-IO-Socket-SSL perl-Time-HiRes perl-Digest-MD5 perl-ExtUtils-MakeMaker -y
#下载工具集
wget https://www.percona.com/downloads/percona-toolkit/2.2.18/tarball/percona-toolkit-2.2.18.tar.gz
#解压缩
tar -xvf percona-toolkit_2.2.18.tar.gz
#进入目录
cd percona-toolkit-2.2.18/
#执行perl脚本
perl Makefile.PL
#编译
make
#安装
make install
第二步:执行命令进行检测
通过使用pt-table-checksum命令来进行检测,注意检测时需要指定一个表(表名可自定义),这个表用来记录差异点 为后续同步数据作为参考,这里假设要检测test数据库里面的table1表是否不同步。
pt-table-checksum --nocheck-binlog-format --nocheck-replication-filters --replicate=test.checksums --databases=test --tables=table1 --host=172.16.0.21 --port=3306 --user=check_user --password=123456
关于以上命令的解释如下:
--nocheck-replication-filters :不检查复制过滤器,建议启用,这样我们可以自定义检查哪个数据库的数据,否则将会检查mysql所有被同步的数据库。
--no-check-binlog-format : 不检查复制的binlog模式,要是binlog模式是ROW,则会报错。
--replicate-check-only :只显示不同步的信息,根据情况可加可不加,不加就会显示全部表的信息。
--replicate= :把checksum的信息写入到指定表中,建议直接写到被检查的数据库当中。
--databases= :指定需要被检查的数据库,多个则用逗号隔开,建议一个一个检查。
--tables= :指定需要被检查的表,多个用逗号隔开
--host= :Master的地址
--user= :用户名,也可以使用root用户,或者自己创建用户赋予查询,修改,删除,同步权限,注意数据库权限也要赋予
--password= :密码
--Port= :端口
在主库服务器执行以上命令之后 test数据库里面多了一个表checksums记录了哪些表不同步的信息。同时执行命令后命令输出如下信息:
# A software update is available:
# * The current version for Percona::Toolkit is 3.0.5
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
09-02T11:59:07 0 1 1266622 14 0 5.983 test.table1
[root@db-001-server ~]#
部分字段的解释如下
TS :完成检查的时间。
ERRORS :检查时候发生错误和警告的数量。
DIFFS :0表示一致,1表示不一致。当指定--no-replicate-check时,会一直为0,当指定--replicate-check-only会显示不同的信息。
ROWS :表的行数。
CHUNKS :被划分到表中的块的数目。
SKIPPED :由于错误或警告或过大,则跳过块的数目。
TIME :执行的时间。
TABLE :被检查的表名。
以上结果中DIFFS为1代表主库和从库之间的数据有差异,接下来就是如何修复差异数据,我们使用另一个命令:pt-table-sync
pt-table-sync h=172.16.0.21,u=check_user,p=123456,P=3306 --databases=test --tables=table1 --replicate=test.checksums --print
上面命令里面的参数和之前的pt-table-checksum
命令里面的一样,只是使用了简写的方式,注意最后一个参数 --print 这个很重要 这个--print会先把要执行修复操作的SQL文打印出来并不真正执行,用户可以查看SQL文。这里需要说一下 pt-table-sync
修复数据差异的原理:
这个命令首先会根据pt-table-checksum
命令比较的结果也就是checksums表的记录去自动生成相关的SQL文,比如主库表里面多了一条记录则会生成一个SQL文 类似于 replace into table1(xx,xx,xx) values(yy,yy,yy)
这里使用replace into就是有记录则删除再插入,无记录则直接插入,这样一来主库执行了该条SQL之后记录不变,但是因为主从同步的原因从库也会执行这条记录,这样就能够达到主库和从库数据一致了。需要注意一个前提就是表必须有主键才行
如果主库里面没有了某条记录而从库里面还有记录 因为我们要参考主库作为最终依据则此时使用命令会生成DELETE FROM TABLE1 WHERE ID = XX的SQL文(记住这个原理,后续有用处)
如果确认SQL没问题想执行修复 只需要执行如下语句(把--print替换成了 --execute)
pt-table-sync h=172.16.0.21,u=check_user,p=123456,P=3306 --databases=test --tables=table1 --replicate=test.checksums --execute
修复完毕之后可以重新执行一下pt-table-checksum
命令看是否一致了。
以上便是解决主从不同步的方式,如果想要解决多张表则只需要在--tables后面指定多张表,如果想要修复整个库则只需要去掉--tables则默认检查整个数据库的所有表
主主同步留下的一个问题:如果部分表想要参考另一个库的数据,该如何做?
这个问题是我自己亲身遇到的,我的mysql数据库做的是主主同步,A,B两个数据库互为主库双向同步。因此发现数据不一致时需要保持两个库的数据汇总操作
我是这样解决的:
首先在A库服务器上面执行完pt-table-checksum
之后执行pt-table-sync
发现里面有DELETE SQL文,意思是要删除某些数据,因为此时A库里面部分数据比B库少,那么怎么办呢,这里我单独提取了DELETE SQL文的主键,然后去B库查询这些数据并复制成INSERT 语句(使用Navicat工具的同学应该知道有这个功能,把查询到的数据复制成插入SQL文),然后我把这些插入SQL文改成replace into的方式(只需要替换insert为replace即可) 然后在B库执行这些SQL文,此时A库的这个表就拥有这些数据了。
那么重新执行pt-table-checksum
之后执行pt-table-sync
打印出来的SQL文只剩下replace into了 这时可以放心执行修复了。这只是一种思路用于数据量不大的情况。如果数据量大该怎么办呢?可以在B库服务器安装工具集然后执行同样的操作并且复制出replace into sql文在B库执行。A B2个库来回切换着同步一样可以解决问题。