当前位置: 首页 > 科技观察

如何使用PerconaToolkit解决Mysql主从不同步的问题

时间:2023-03-15 20:00:08 科技观察

由于各种原因,mysql主从架构经常会出现数据不一致的情况,大致可以归纳为:1:将数据写入备份数据库2:执行非确定性查询3:回滚事务表和非事务表混合的事务4:Binlog或中继日志数据损坏和数据不同步对应用程序的危害是致命的。当主从数据不一致时,常见的解决办法是先从数据库下线,然后半夜找个时间停止应用,重新执行同步。如果数据库很大,工作量可想而知,会让人崩溃。本文介绍使用percona-toolkit工具检查并重新同步MySQL主从数据库的同步状态。一:安装percona-toolkit#yum-yinstallperl-Time-HiRes#wgethttp://www.percona.com/downloads/percona-toolkit/2.2.13/tarball/percona-toolkit-2.2.13.tar.gz#tar-zxvpfpercona-toolkit-2.2.13.tar.gz#cdpercona-toolkit-2.2.13#perlMakefile.PL#make#makeinstall二:修改mysql的binlog格式binlog_format参数为行格式mysql的binlog日志有三种格式,分别是语句、混合和ROW!1.语句:每一条会修改数据的sql都会记录在binlog中。优点:无需记录每一行的变化,减少binlog日志量,节省IO,提高性能。(与row相比,能节省多少性能和日志量取决于应用的SQL情况。通常情况下,以row格式修改或插入相同记录产生的日志量要比Statement产生的日志量小,但是考虑到如果条件更新操作,以及删除整表,altertable等操作,ROW格式会产生大量的日志,所以在考虑是否使用ROW格式日志时,应该根据应用的实际情况,产生的日志量会增加多少,以及由此带来的I/O性能问题。)缺点:由于只记录了执行语句,为了让这些语句在slave上正确运行,需要在每条语句执行时记录一些相关信息,以保证所有语句都能被slave获取到并在主端执行。同样的结果。另外,对于mysql的replication,像一些特定的函数,slave可以和master保持一致,也会有很多相关的问题(比如sleep()函数、last_insert_id()、用户自定义函数(udf)会有问题)。2、Row不记录sql语句上下文的相关信息,只保存哪条记录被修改了。优点:binlog不需要记录执行的SQL语句的上下文相关信息,只需要记录记录被修改成什么。所以rowlevel日志内容会清楚的记录每一行数据修改的细节。并且不会出现某些情况下存储过程、函数、触发器调用和触发器无法正确复制的问题缺点:当所有执行的语句都记录在日志中时,会在每一行中记录修改为记录,这样可能会产生日志内容很多,比如一条update语句,修改多条记录,binlog中每次修改都会有一条记录,会造成大量的binlog日志,尤其是在执行altertable之类语句的时候,每条记录由于表结构的修改而改变,表的每条记录都会记录在日志中。3.混合就是以上两个层次的混合使用。一般语句修改使用statment格式保存binlog。比如一些功能,语句无法完成主从复制操作,采用行格式保存binlog。MySQL会根据具体的每一项执行sql语句来区分要记录的日志形式,即Statement和Row二选一。新版MySQLSquadron的行级模式也进行了优化,并不是所有的修改都会记录在行级,比如表结构发生变化时,会在语句模式下记录。对于update、delete等修改数据的语句,仍然会记录所有行的变化。修改主从数据库my.cnf文件相关配置项如下:binlog_format=ROW#p#三:使用pt-table-checksum工具校验数据一致性使用参考:假设192.168.1.205为主数据库,而192.168.1.207就是它的从库,端口是3306。1.首先验证#pt-table-checksum--user=root--password=123456\--host=192.168.1.205--port=3306\--databases=test--tables=t2--recursion-method=processlist\--no-check-binlog-format--nocheck-replication-filters\--replicate=test.checksums2。根据校验结果,只修复192.168.1.207从库和主库不一致的地方:#pt-table-sync--execute--replicate\test.checksums--sync-to-masterh=192.168.1.207,P=3306,u=根,p=1234563。修复后,再次检查。执行第一步的语句。4、查看修复结果:登录192.168.1.207,执行如下sql语句,如果返回为空,表示修复成功:SELECT*FROMtest.checksumsWHEREmaster_cnt<>this_cntORmaster_crc<>this_crcORISNULL(master_crc)<>ISNULL(this_crc)各参数含义--nocheck-replication-filters:不检查复制过滤器,建议启用。稍后您可以使用--databases指定要检查的数据库。--no-check-binlog-format:不检查复制的binlog模式。如果binlog模式是ROW,会报错。--replicate-check-only:只显示不同步的信息。--replicate=:将checksum信息写入指定表,建议直接写入checked数据库。--databases=:指定需要检查的数据库,多个以逗号分隔。--tables=:指定要检查的表,以逗号分隔h=127.0.0.1:Master的地址u=root:用户名p=123456:密码P=3306:端口#p#我们来模拟下面是pt-table-主从数据库不同步时的校验和。为了方便,这里使用testschema1:在master数据库上建表,插入测试数据mysql>createtablet2(idintprimarykey,namevarchar(100)notnull,salaryint);mysql>CREATEPROCEDUREtest_insert()BEGINDECLAREiINTDEFAULT0;WHILEi<10000DOINSERTIINTOt2VALUES(i,CONCAT('Employee',i),i);SETi=i+1;ENDWHILE;END;;mysql>CALLtest_insert();检查当前数据是否正常从数据库同步。从数据库中删除一半数据mysql>deletefromt2whereid>5000;QueryOK,4999rowsaffected(0.14sec)mysql>selectcount(*)fromt2;+----------+|count(*)|+---------+|5001|+----------+1rowinset(0.01sec)2:使用pt-table-checksum工具进行验证:#pt-table-checksum--user=root--password=123456\--host=192.168.1.205--port=3306\--databases=test--tables=t2--recursion-method=processlist\--no-check-binlog-format--nocheck-replication-filters\--replicate=test.checksums3:登录从库查询checksum表mysql>SELECT*FROMtest.checksumsWHEREmaster_cnt<>this_cntORmaster_crc<>this_crcORISNULL(master_crc)<>ISNULL(this_crc)4:使用pt-table-sync工具进行数据再同步#pt-table-sync--execute--replicate\test.checksums--sync-to-masterh=192.168.1.207,P=3306,u=root,p=1234565:验证数据库中的数据,中文“员工”变成了“??”查看主数据库,发现出现了同样的情况,中文“employee”变成了“??”,猜测与字符集设置有关。然后查看数据库字符集设置,发现测试库的字符集不是utf8。在主从库my.cnf文件中添加如下配置项,重启数据库实例character_set_client=utf8character_set_server=utf8。重新执行以上1-4步,发现一切正常!关键第4步添加--charset=utf8参数#pt-table-sync--execute--replicate\test.checksums--charset=utf8\--sync-to-masterh=192.168.1.207,P=3306,u=根,p=123456