mysql主从同步(2)-问题梳理

 

以前详细介绍了Mysql主从复制的原理和部署过程,在mysql同步过程当中会出现不少问题,致使数据同步异常。
如下梳理了几种主从同步中可能存在的问题:
1)slave运行过慢不能与master同步,也就是MySQL数据库主从同步延迟
MySQL数据库slave服务器延迟的现象是很是广泛的,MySQL复制容许从机进行SELECT操做,可是在实际线上环境下,因为从机延迟的关系,很难将读取操做转向到从机。这就致使了有了如下一些潜规则:“实时性要求不高的读取操做能够放到slave服务器,实时性要求高的读取操做放到master服务器”,“从机仅能作前一天的统计类查询”。
slave滞后即slave不能快速执行来自于master的全部事件,从而不能避免更新slave数据延迟。
mysql的master-slave架构中master仅作写入、更新、删除操做,slave作select操做。形成slave滞后的缘由有不少。
slave同步延迟的原理
MySQL的主从复制都是单线程的操做,主库对全部DDL和DML产生的日志写进binlog,因为binlog是顺序写,因此效率很高。
Slave的IO Thread线程从主库中bin log中读取取日志。
Slave的SQL Thread线程将主库的DDL和DML操做事件在slave中重放。DML和DDL的IO操做是随即的,不是顺序的,成本高不少。
因为SQL Thread也是单线程的,若是slave上的其余查询产生lock争用,又或者一个DML语句(大事务、大查询)执行了几分钟卡住了,那么全部以后的DML会等待这个DML执行完才会继续执行,这就致使了延时。也许有人会质疑:主库上那个相同的DDL也会执行几分钟,为何slave会延时?缘由是master能够并发执行,而Slave_SQL_Running线程却不能够。
slave同步延迟的可能缘由
    1--slave的I/O线程推迟读取日志中的事件信息;最多见缘由是slave是在单线程中执行全部事务,而master有不少线程能够并行执行事务。
    2--带来低效链接的长查询、磁盘读取的I/O限制、锁竞争和innodb线程同步启动等。
    3--Master负载;Slave负载
    4--网络延迟
    5--机器配置(cpu、内存、硬盘)
(主从同步延迟怎么产生的?)总之,当主库的TPS并发较高时,产生的DDL数量超过slave一个sql线程所能处理的承受范围时,主从同步就会产生延时;或者当slave中有大型query语句产生了锁等待也会产生延时。
如何查看同步延迟
    1--能够经过比对master、slave上的日志位置
    2--经过"show slave status"查看Seconds_Behind_Master的值,这个值表明主从同步延迟的时间,值越大说明延迟越严重。值为0为正常状况,正值表示已经出现延迟,数字越大从库落后主库越多。
    3--使用percona-toolkit的pt-hearbeat工具进行查看。
减小同步延迟的操做方案
    1--减小锁竞争
若是查询致使大量的表锁定,须要考虑重构查询语句,尽可能避免过多的锁。
    2--负载均衡
搭建多少slave,而且使用lvs或nginx进行查询负载均衡,能够减小每一个slave执行查询的次数和时间,从而将更多的时间用于去处理主从同步。
    3--salve较高的机器配置
    4--Slave调整参数
为了保障较高的数据安全性,配置sync_binlog=1,innodb_flush_log_at_trx_commit=1等设置。而Slave能够关闭binlog,innodb_flush_log_at_trx_commit也能够设置为0来提升sql的执行效率(这两个参数很管用)
    5--并行复制
即有单线程的复制改为多线程复制。
从库有两个线程与复制相关:io_thread 负责从主库拿binlog并写到relaylog, sql_thread 负责读relaylog并执行。
多线程的思路就是把sql_thread 变成分发线程,而后由一组worker_thread来负责执行。
几乎全部的并行复制都是这个思路,有不一样的,即是sql_thread 的分发策略。
MySQL5.7的真正并行复制enhanced multi-threaded slave(MTS)很好的解决了主从同步复制的延迟问题。html

2)slave同步状态中出现Slave_IO_Running: NO (通常是下面的缘由2形成的)
报错:Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'mysql

缘由1:清理数据致使主从库不一样步(前提是主库的binlog日志没有被暴力删除或错误删除,即要确保正在使用的那个最新binlog文件在master主库机器上存在)。
解决办法:
1)先进入slave中执行:"slave stop;"来中止从库同步;
2)再去master中执行:"flush logs;"来清空日志;
3)而后在master中执行:"show master status;"查看下主库的状态,主要是日志的文件和position;
4)而后回到slave中,执行:"CHANGE MASTER TO ......执行同步指令
 
缘由2:该错误发生在从库的io进程从主库拉取日志时,发现主库的mysql_bin.index文件中第一个文件不存在。出现此类报错多是因为你的slave 因为某种缘由中止了好长一段
时间,当你重启slave 复制的时候,在主库上找不到相应的binlog ,会报此类错误。或者是因为某些设置主库上的binlog被删除了,致使从库获取不到对应的binglog file。
解决办法:
1)为了不数据丢失,须要从新进行slave同步操做。
2)注意主库binlog的清理策略,选择基于时间过时的删除方式仍是基于空间利用率的删除方式。
3)记住最好不要使用"rm -rf"命令删除binlog file,这样不会同步修改mysql_bin.index 记录的binlog 条目。在删除binlog的时候确保主库保留了从库"show slave status"
  的Relay_Master_Log_File对应的binlog file。任什么时候候都不能删除正在使用的那个最新binlog文件;最好把bin-log文件不要删除,最好给备份出来。
 
缘由2的状况下,使用缘由1的处理方案显然是解决不了的!此时的解决方案:
在从库上执行:
mysql> stop slave;
mysql> reset slave;
mysql> start slave;
mysql> show slave status \G;

3)slave同步状态中出现Slave_IO_Running: Connecting
致使这个错误的缘由通常是:
    1--网络不通
    2--权限问题(链接master的用户名和密码跟master受权不一致)
    3--链接时用的log file和pos节点跟"show master status"的结果不一致nginx

4)slave同步状态中出现Slave_SQL_Running: No ,即slave不一样步!
解决办法:
第一种方法:忽略错误后,继续同步
该方法适用于主从库数据相差不大,或者要求数据能够不彻底统一的状况,数据要求不严格的状况(下面均为在slave机器上的操做)
mysql> stop slave;
mysql> set global sql_slave_skip_counter =1;   //表示跳过一步错误,后面的数字可变;或者在my.cnf里添加slave-skip-errors = all(上面已在配置中添加)
mysql> start slave;
mysql> show slave status\G      //查看:
第二种方法:从新作主从,彻底同步
该方法适用于主从库数据相差较大,或者要求数据彻底统一的状况
1--master主库上操做
mysql> flush tables with read lock;  //进行锁表,防止数据写入。注意该处是锁定为只读状态,语句不区分大小写
#mysqldump --lock-all-tables --all-databases --flush-logs --master-data=2 > /root/allsql.sql   //主库彻底备份(若是是指定库同步,就备份指定库),注意数据库备份必定要按期进行,确保数据万无一失
mysql> show master status;      //查看master状态,注意log file和pos节点,slave同步会用到
# scp mysql.bak.sql root@192.168.1.102:/tmp/        //把备份文件传到slave从库机器,进行数据恢复
2--slave从库操做
mysql> stop slave;
mysql> source /tmp/mysql.bak.sql
mysql> change master to master_host = '192.168.1.101', master_user = 'slave', master_port=3306.......;
mysql> start slave;
mysql> show slave status\G
.......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
此种方法中最为关键主要有两步:
①主服务器上锁表作彻底备份,并滚动日志;
②从服务器上进行半道恢复.sql

5)slave中继日志relay-log损坏?
什么是中继日志?
relay-log存放在从服务器上,从服务器将主服务器的二进制日志文件拷贝到本身的主机上放在中继日志中,而后调用SQL线程按照拷中继日志文件中的二进制日志文件执行以便就可达到数据的同步 。
如何中继日志避免:
mysql 5.6版本后,在my.cnf文件中开启relay_log_recover=1便可避免。数据库

6)slave链接超时且从新链接频繁
如有多少slave,且没有设置server_id或两个slave设置相同的server_id,将有可能会出现服务器的ID冲突。这种状况下,其中一台slave可能会频繁超时或丢失后从新链接序列。
因此必定要确保每台slave及master在my.cnf中都要设置不同的server_id。安全

7)主库与从库使用不一样的存储引擎形成不一样步bash

8)从库同步时,提示表不存在
错误:Last_Error: Error executing row event: 'Table 'test.t1' doesn't exist'
解决方法:在从库重建这张表。服务器

9)max_allowed_packet设置太小致使slave报错
max_allowed_packet默认是16M,主从库的max_allowed_packet值和备库上的不匹配。
在这状况下,主库可能会记录一个备库认为过大的包。当备库获取到该二进制日志事件时,可能会碰到各类问题,如无限报错和重试、中继日志损坏等。
具体表现:
从库的Slave_IO_Thread死掉了,查看后,出现如下错误提示:
Got a packet bigger than 'max_allowed_packet' bytes
很明显是因为max_allowed_packet的设置过小致使的,而后查检主从库上的设置,主库的设置大于从库,由于max_allowed_packet是动态参数,先调整从库上的max_allowed_packet 与主库相同,从新单独启动I/O线程就正常了。
原理说明:binlog的事件以RBR格式记录,且当前的事件长度大于了从库的max_allowed_packet, 致使没法Slave IO不能正常读取master binlog event.网络

10)在master上删除一条记录时出现的故障
在master上删除一条记录后,slave上因找不到这条记录而报错。
解决方法:
因为主库上已经对这条语句进行了删除操做,故能够跳过。
在这种状况下,说明主从同步可能数据会有不一致的状况发生,因此须要使用pt-table-checksum进行数据库一致性比对。
(参考:mysql主从同步(3)-percona-toolkit工具(数据一致性监测、延迟监控)使用梳理多线程

11)在master更新一条记录,而slave却找不到。
主从数据不致时,master有某条记录,但在salve上没有这条记录,若在master上进行更新这条记录,则在slave中可能报错。
解决方法:
   1--根据从库发生异常的位置,查主库上的二进制日志。
   2--根据主库二进制日志信息,找到更新后的整条记录。
   3--在从库上执行在主库上找到的记录信息,进行insert操做。
   4--跳过这条语句,再同步slave。
   5--使用pt-table-checksum查看主从库表数据否一致。

12)删除登陆mysql后的操做记录

[root@mysql ~]# ll /home/mysql/.mysql_history 
-rw------- 1 mysql mysql 1255 Jun 15 18:18 /home/mysql/.mysql_history
[root@mysql ~]# >/home/mysql/.mysql_history

13)同步时出现报错"Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'"

在从机mysql上查看slave状态,报错以下:
Mysql> show slave status\G;
......
Slave_IO_Running: No
Slave_SQL_Running: Yes
......
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'

解决办法:
在主机mysql上执行:
Mysql> FLUSH TABLES WITH READ LOCK;
Mysql> flush logs;
Mysql> show master status;

记下File, Position。

而后在从机mysql上执行同步操做(根据上面记住的File和Position)
Mysql> stop slave;
Mysql> change master to master_host='主机mysqlip',master_user='受权同步的用户',master_password='受权同步密码',master_log_file='记下的File',master_log_pos=记下的Position;
Mysql> start slave;
Mysql> show slave status\G;
......
Slave_IO_Running: No
Slave_SQL_Running: Yes

而后在主机mysql上进行解锁
mysql> unlock tables; 

14)服务器重启或mysql服务重启后,如何恢复mysql主从同步关系

当mysql主从同步顺利完成后,若是重启服务器或mysql服务重启后,恢复mysql主从同步关系的正确步骤:
1)主机mysql和从机mysql都要启动mysql服务
# /etc/init.d/mysql start
2) 在从机mysql上进行slave恢复操做
mysql> stop slave;
Query OK, 0 rows affected (0.08 sec)
 
mysql> start slave;
Query OK, 0 rows affected (0.04 sec)
 
mysql> show slave status \G;
......
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
.....

                                                           mysql主从同步(跨机房状况)不一致问题                                                     
1) 网络的延迟
因为mysql主从复制是基于binlog的一种异步复制,经过网络传送binlog文件,理所固然网络延迟是主从不一样步的绝大多数的缘由,特别是跨机房的数据同步出现这种概率很是的大,因此作读写分离,注意从业务层进行前期设计。
2) 主从两台机器的负载不一致
因为mysql主从复制是主数据库上面启动1个io线程,而从上面启动1个sql线程和1个io线程,当中任何一台机器的负载很高,忙不过来,致使其中的任何一个线程出现资源不足,都将出现主从不一致的状况。
3) max_allowed_packet设置不一致
主数据库上面设置的max_allowed_packet比从数据库大,当一个大的sql语句,能在主数据库上面执行完毕,从数据库上面设置太小,没法执行,致使的主从不一致。
4) key自增键开始的键值跟自增步长设置不一致引发的主从不一致。
5) mysql异常宕机状况下,若是未设置sync_binlog=1或者innodb_flush_log_at_trx_commit=1颇有可能出现binlog或者relaylog文件出现损坏,致使主从不一致。
6) mysql自己的bug引发的主从不一样步。
7) 版本不一致,特别是高版本是主,低版本为从的状况下,主数据库上面支持的功能,从数据库上面不支持该功能。

以上就是常见的一些主从不一样步的状况。基于以上状况,先保证max_allowed_packet、自增键开始点和增加点设置一致,再者牺牲部分性能在主上面开启sync_binlog。
对于采用innodb的库,推荐在配置文件中添加下面内容:

innodb_flush_logs_at_trx_commit = 1
innodb-support_xa = 1

同时在从数据库的配置文件中再多添加下面两个参数:

skip_slave_start
read_only
相关文章
相关标签/搜索