MYSQL主从同步异常解决方案

2022-03-1217:24:32数据库教程Comments2,702 views字数 13885阅读模式
MYSQL主从同步异常解决方案
作者 | Love DN 
出品 | 脚本之家(ID:jb51net)

MYSQL主从同步异常解决方案

理论上讲,mysql的主从同步无法保证100%不出现异常,mysql本身并不能保证主从的稳定性,当前较流行的MHA等mysql主从同步解决方案也是尽最大努力保证数据的一致性,出现异常还是要进行人工干预。对于MYSQL加快主从同步的方式,经历了库间并发 - 组提交 - WriteSet等一系列减缓复制延迟的问题,但是很遗憾,主从复制做的在快,也解决不了中途出现异常的情况,本文基于MYSQL采用 binlog和利用组提交方式的前提,探讨在主从复制期间产生异常后,应如何解决,达到防止数据丢失,最终恢复主从关系的目的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html


前提知识

为了方便阅读,我们定义两台服务器分别是A,B,A作为master,B是slaver。(主主原理一样)。在设置主从时,为了防止因配置导致的主从同步问题,最好将主从的参数设置保持一致。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

    1. 主从同步流程文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

      B中有两个重要的线程,一个是I/O线程,负责同步A的binlog日志文件,然后将日志文件写到磁盘,写到磁盘的文件起了个名字,叫中继日志,也就是relaylog;另一个是SQL线程,负责读取relaylog中的sql,在从节点重放SQL,以达到主从同步的目的,当然这里面有很多优化细节,例如组提交模式下的线程模型,如何调节relaylog参数,使得中继日志快速落地等,这不属于本文讨论的范围。mysql就是使用此种方式,将AB数据同步。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

    2. binlog日志格式文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

      binlog都很熟悉,这是mysql执行命令的底牌,不区分存储引擎,就像流水账一样,将mysql引擎层执行的sql,尽可能详细的记录在案。但是太详细,就会使得binlog日志过大,太少,则无法还原真实面貌。那记录的方式就成了关键,MYSQL为我们提供了三种记录方式,使用binlog_format = row|statement|mixed,特定类型下还有一些细微的调节。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

      通过以下命令可以明文显示binlog的内容文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

      mysqlbinlog  -vv  --base64-output=DECODE-ROWS  mysql-bin.000001文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

      下面以tb_test(id, stu_id, name)这个表为例子
      (1)statement: 这种方式最好理解,直接将sql语句记录在binlog中,但是缺点很明显,例如insertinto tb_test values(1, uuid(), 'nnn');这样从在执行时,导致id主从不一致
      	# at 609
          #210922 14:01:36 server id 1  end_log_pos 733 CRC32 0x65647349  Query   thread_id=2     exec_time=0     error_code=0
          SETTIMESTAMP=1632290496/*!*/;
          insertinto tb_test values(1, uuid(), 'nnn')
          /*!*/;
          # at 733
          #210922 14:01:36 server id 1  end_log_pos 764 CRC32 0x0829c9d1  Xid = 21
          COMMIT/*!*/;
      
      (2)row:这是mysql默认的方式,不会出现statement的问题,单同样有缺点,在update时,会将所有的列都输出到binlog日志中,导致 	binlog的增长量很快,例如现有表 tb_test(id, stu_id, name),在执行update tb_test setname= 'xxx'whereid=1;真正记录binlog的是
      	# at 294
          #210922 14:11:33 server id 1  end_log_pos 353 CRC32 0x52746c43  Table_map: `test_db`.`tb_test` mapped to number 108
          # at 353
          #210922 14:11:33 server id 1  end_log_pos 481 CRC32 0x4e0adf53  Update_rows: table id 108 flags: STMT_END_F
          ### UPDATE `test_db`.`tb_test`
          ### WHERE
          ###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
          ###   @2='28851e78-1b6b-11ec-a9d1-d8c497b8d38b' /* VARSTRING(233) meta=233 nullable=1 is_null=0 */
          ###   @3='xx' /* VARSTRING(22) meta=22 nullable=1 is_null=0 */
          ### SET
          ###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
          ###   @2='28851e78-1b6b-11ec-a9d1-d8c497b8d38b' /* VARSTRING(233) meta=233 nullable=1 is_null=0 */
          ###   @3='xxdd' /* VARSTRING(22) meta=22 nullable=1 is_null=0 */
          # at 481
          #210922 14:11:33 server id 1  end_log_pos 512 CRC32 0x59324426  Xid = 6
          COMMIT/*!*/;
      	这样在where和set后将所有字段都列出,当然也能精简binlog的输出,在ROW模式下,使用	 	binlog_row_image=minimal|full|noblob,其中full是默认的,如上,将镜像前后都设置,所谓镜像就是表在执行update前的数据情况,where记录了镜像前的数据(BI),set记录镜像后的数据(AI),binlog中对于insert只有AI,delete只有BI,而update包含BI和AI,使用minimal后,如下:
      	# at 294
          #210922 14:14:21 server id 1  end_log_pos 353 CRC32 0x029a51df  Table_map: `test_db`.`tb_test` mapped to number 108
          # at 353
          #210922 14:14:21 server id 1  end_log_pos 441 CRC32 0x6cc35569  Update_rows: table id 108 flags: STMT_END_F
          ### UPDATE `test_db`.`tb_test`
          ### WHERE
          ###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
          ###   @2='3d3475ee-1b6c-11ec-9c36-d8c497b8d38b' /* VARSTRING(233) meta=233 nullable=1 is_null=0 */
          ###   @3='nnn' /* VARSTRING(22) meta=22 nullable=1 is_null=0 */
          ### SET
          ###   @3='xxdd' /* VARSTRING(22) meta=22 nullable=1 is_null=0 */
          # at 441
          #210922 14:14:21 server id 1  end_log_pos 472 CRC32 0x1d0bc509  Xid = 5
          COMMIT/*!*/;
          SET @@SESSION.GTID_NEXT= 'AUTOMATIC'/* added by mysqlbinlog *//*!*/;
          DELIMITER ;
          为什么使用了minimal,镜像前仍然是全量数据,因为mysql规定,如果表没有主键,则镜像前依然和full一样,这里给tb_test增加个主键,altertable tb_test add PRIMARY key(id);在执行update
          # at 797
          #210922 14:16:03 server id 1  end_log_pos 856 CRC32 0x49bd88c1  Table_map: `test_db`.`tb_test` mapped to number 109
          # at 856
          #210922 14:16:03 server id 1  end_log_pos 904 CRC32 0xde32ec90  Update_rows: table id 109 flags: STMT_END_F
          ### UPDATE `test_db`.`tb_test`
          ### WHERE
          ###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
          ### SET
          ###   @3='xxdds' /* VARSTRING(22) meta=22 nullable=1 is_null=0 */
          # at 904
          #210922 14:16:03 server id 1  end_log_pos 935 CRC32 0xdacdff35  Xid = 9
          COMMIT/*!*/;
      (3)mixed:两者的结合,一般的SQL语句以statement形式展示sql语句,当涉及uuid等函数时,使用row的形态;
      在使用row和mixed时,可能会问,真正执行的sql语句无法从binlog中展示,很幸运,mysql为我们提供了binlog_rows_query_log_events参数,设置ON|1时,sql语句会以注释的形式写在binlog中
      
      生产建议使用binlog_format=row 配合 binlog_row_image=minimal
      
    3. binlog日志内容文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html
-- binlog开头用语
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#210922 14:46:31 server id 1  end_log_pos 123 CRC32 0x97df49ac  Start: binlog v 4, server v 5.7.27-0kord0.16.04.1k2-log created 210922 14:46:31 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
# at 123
#210922 14:46:31 server id 1  end_log_pos 154 CRC32 0x85340b11  Previous-GTIDs
# [empty]

-- 创建数据库
# at 154
#210922 14:48:11 server id 1  end_log_pos 219 CRC32 0x0ccb3436  Anonymous_GTID  last_committed=0        sequence_number=1       rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 219
#210922 14:48:11 server id 1  end_log_pos 402 CRC32 0xdfce7c53  Query   thread_id=2     exec_time=0     error_code=0
SETTIMESTAMP=1632293291/*!*/;
SET @@session.pseudo_thread_id=2/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATEDATABASE/*!32312 IF NOT EXISTS*/`my_db`/*!40100 DEFAULT CHARACTER SET utf8 */
/*!*/;

-- 创建表
# at 402
#210922 14:54:57 server id 1  end_log_pos 467 CRC32 0x063edb06  Anonymous_GTID  last_committed=1        sequence_number=2       rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 467
#210922 14:54:57 server id 1  end_log_pos 637 CRC32 0xa22dd94a  Query   thread_id=2     exec_time=0     error_code=0
use`my_db`/*!*/;
SETTIMESTAMP=1632293697/*!*/;
createtable tb_test (idint,stu_id varchar(64),namevarchar(32)) ENGINE=INNODB
/*!*/;

-- insert表数据
# at 637
#210922 14:56:18 server id 1  end_log_pos 702 CRC32 0xa55b302a  Anonymous_GTID  last_committed=2        sequence_number=3       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 702
#210922 14:56:18 server id 1  end_log_pos 782 CRC32 0x15ecbfb9  Query   thread_id=2     exec_time=0     error_code=0
SETTIMESTAMP=1632293778/*!*/;
BEGIN
/*!*/;
# at 782
#210922 14:56:18 server id 1  end_log_pos 846 CRC32 0xf0b67ceb  Table_map: `my_db`.`tb_test` mapped to number 112
# at 846
#210922 14:56:18 server id 1  end_log_pos 897 CRC32 0xce3a064c  Write_rows: table id 112 flags: STMT_END_F
### INSERT INTO `my_db`.`tb_test`
### SET
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */
###   @2='1111' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='nanan' /* VARSTRING(96) meta=96 nullable=1 is_null=0 */
# at 897
#210922 14:56:18 server id 1  end_log_pos 928 CRC32 0x1a1f19ed  Xid = 17
COMMIT/*!*/;

-- update表
# at 928
#210922 14:57:31 server id 1  end_log_pos 993 CRC32 0x638f8e2f  Anonymous_GTID  last_committed=3        sequence_number=4       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 993
#210922 14:57:31 server id 1  end_log_pos 1073 CRC32 0x5234432b         Query   thread_id=2     exec_time=0     error_code=0
SETTIMESTAMP=1632293851/*!*/;
BEGIN
/*!*/;
# at 1073
#210922 14:57:31 server id 1  end_log_pos 1137 CRC32 0x499487e2         Table_map: `my_db`.`tb_test` mapped to number 112
# at 1137
#210922 14:57:31 server id 1  end_log_pos 1195 CRC32 0x521abeb5         Update_rows: table id 112 flags: STMT_END_F
### UPDATE `my_db`.`tb_test`
### WHERE
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */
###   @2='1111' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='nanan' /* VARSTRING(96) meta=96 nullable=1 is_null=0 */
### SET
###   @3='xxxx' /* VARSTRING(96) meta=96 nullable=1 is_null=0 */
# at 1195
#210922 14:57:31 server id 1  end_log_pos 1226 CRC32 0xb9a42b3a         Xid = 18
COMMIT/*!*/

-- delete
# at 1226
#210922 14:58:31 server id 1  end_log_pos 1291 CRC32 0x913de440         Anonymous_GTID  last_committed=4        sequence_number=5       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 1291
#210922 14:58:31 server id 1  end_log_pos 1371 CRC32 0x29f9b016         Query   thread_id=2     exec_time=0     error_code=0
SETTIMESTAMP=1632293911/*!*/;
BEGIN
/*!*/;
# at 1371
#210922 14:58:31 server id 1  end_log_pos 1435 CRC32 0x008566a7         Table_map: `my_db`.`tb_test` mapped to number 112
# at 1435
#210922 14:58:31 server id 1  end_log_pos 1485 CRC32 0xb2abadc4         Delete_rows: table id 112 flags: STMT_END_F
### DELETE FROM `my_db`.`tb_test`
### WHERE
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */
###   @2='1111' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='xxxx' /* VARSTRING(96) meta=96 nullable=1 is_null=0 */
# at 1485
#210922 14:58:31 server id 1  end_log_pos 1516 CRC32 0xdaabfcd8         Xid = 19
COMMIT/*!*/;

-- binlog文件结尾用语
SET @@SESSION.GTID_NEXT= 'AUTOMATIC'/* added by mysqlbinlog *//*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

由上面日志可以发现两个问题,文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

(1)所有的增删改,都有一句/!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED//!/;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

这是什么情况,将事物的隔离级别设置成了读已提交,MYSQL默认的不是RR吗?网上找了下,没找到原因,我的理解:mysql本身事务开启是从执行sql开始,而binlog的记录是从commit后记录,文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

(2)增删改都会产生5个事件,每个事件都以at 事件起点 开头;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

这里以update为例子,说明binlog的日志内容文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

-- 事件起点,以at开头,任何增删改前面都会有两个at,一个标识last_committed,sequence_number信息,一个是thread_id,exec_time信息
# at 928
-- 事件发生的时间 然后标识server id,是从哪台mysql产生的事件,last_committed时提交事务,组提交的方式,两次事务可能一样
#210922 14:57:31 server id 1  end_log_pos 993 CRC32 0x638f8e2f  Anonymous_GTID  last_committed=3        sequence_number=4    rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
-- 第二次at,标识执行线程id,和事务执行时间,错误码,0代表无错误,真正的事务开始时间TIMESTAMP,BEGIN
# at 993
#210922 14:57:31 server id 1  end_log_pos 1073 CRC32 0x5234432b         Query   thread_id=2     exec_time=0     error_code=0
SETTIMESTAMP=1632293851/*!*/;
BEGIN
/*!*/;
-- 表明操作的是tb_test表,此表的ID是112,这值并不是不变的,是表载入内存时临时分配的数值
# at 1073
#210922 14:57:31 server id 1  end_log_pos 1137 CRC32 0x499487e2         Table_map: `my_db`.`tb_test` mapped to number 112
-- 表明事件类型,Update_rows/Delete_rows/Write_rows
# at 1137
#210922 14:57:31 server id 1  end_log_pos 1195 CRC32 0x521abeb5         Update_rows: table id 112 flags: STMT_END_F
### UPDATE `my_db`.`tb_test`
### WHERE
###   @1=1 /* INT meta=0 nullable=1 is_null=0 */
###   @2='1111' /* VARSTRING(192) meta=192 nullable=1 is_null=0 */
###   @3='nanan' /* VARSTRING(96) meta=96 nullable=1 is_null=0 */
### SET
###   @3='xxxx' /* VARSTRING(96) meta=96 nullable=1 is_null=0 */
-- 对应的Xid事务ID
# at 1195
#210922 14:57:31 server id 1  end_log_pos 1226 CRC32 0xb9a42b3a         Xid = 18
COMMIT/*!*/

任何一个事务都是以BEGIN,到COMMIT的过程,中间可能会涉及事务执行时间,事件ID,事件类型,表ID等。
增删改的流程可以粗略的记为:last_committed -> thread -> table -> event(含SQL) -> Xid,对应的
showbinlogeventsin'mysql-bin.000001';中的Event_type列,其他的语句从这五种类型中都能找到答案。
1. Anonymous_Gtid: 包含last_committed,sequence_number,rbr_only设置GTID_NEXT
2. Query:包含thread_id,exec_time,error_code
3. Table_map:表名和ID
4. Update_rows/Delete_rows/Write_rows
5. Xid
同步异常解决方案

由第1条主从同步流程,可以看出重点在于两个线程,所以查看主从是否异常的时候,往往关注 show slave status\G中文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

如上两个线程的运行状态,如果存在一个No,则说明主从已经停止,异常已经产生。为了方便后续查看同步情况,这里先说明各字段的含义文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

Slave_IO_State: Waiting for master to send event
                  Master_Host: 1.1.1.1 					-- master服务器IP
                  Master_User: repl					-- 主从同步用户
                  Master_Port: 3306						-- 主库端口
                Connect_Retry: 60						-- 建立连接尝试次数
              Master_Log_File: mysql-bin.000014  -- master的binlog日志,在master上执行show master status查看
          Read_Master_Log_Pos: 33603949			 -- 中继器读到的master binlog的位置
               Relay_Log_File: relay-bin.000014	-- 从库中继器的日志文件
                Relay_Log_Pos: 367						-- 中继日志读到的位置
        Relay_Master_Log_File: mysql-bin.000014			-- 当前中继读到的master的binlog文件
             Slave_IO_Running: Yes	-- I/O线程状态
            Slave_SQL_Running: Yes  -- SQL线程状态
              Replicate_Do_DB: 
          Replicate_Ignore_DB: mysql,information_schema,performance_schema,sys -- 主从同步忽略的库
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 33603949			-- SQL线程执行到的Relay_Master_Log_File文件的位置
              Relay_Log_Space: 741
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0			-- 主从数据同步间隔时间
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2			-- master库的serverId,在my.cnf中配置的,主从不能设置一样
                  Master_UUID: ccc05185-0bb1-11ec-9019-6c92bf04787e
             Master_Info_File: mysql.slave_master_info	-- master的信息,这里根据master_info_repository配置决定
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version:

关于主从同步异常,我们会从一下几个思路去思考文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

(1)根据业务,将不需要的异常编码排除,例如文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

1032:记录不存在,当更新或删除一个条不存在的记录时,我们可以忽略此异常
1050:数据表已经存在
还有一些个性化的 1062,等,都可以使用slave-skip-errors=1032,1050跳过这些异常,
注意slave-skip-errors=all千万不要这么设置,研发认为这样设置肯定不会出现主从异常,但是很遗憾,这样设置有多重危害:
  1.可能导致主从数据不一致
  2.当I/O线程异常时,例如relaylog,binlog等刷盘时异常,高并发下突然断电等情况,使得日志文件损坏,这类异常仅仅通过跳过是不能解决的

(2)纯SQL执行异常文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

这类异常最好处理,找到执行错误的sql,只需要查看为什么错误,如果对数据一致性不影响,直接在从库执行文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

为了确保无问题,可以查看Relay_Master_Log_File文件的Exec_Master_Log_Pos位置,看下到底是什么问题导致异常,然后执行
stopslave;
setglobal sql_slave_skip_counter=1;
startslave;
跳过此异常

(3)I/O异常情况文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

这类异常比较麻烦,也是本文讲解的重点,分为两种:一种是master的binlog日志异常,二种是slave的relaylog异常。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

我们要做的首先确定Relay_Master_Log_File,这是slave已经同步到的master的binlog日志,通过mysqlbinlog获取该文件的内容,找到最后的eng_log_pos,利用文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

第一个参数是同步的binlog文件,第二个是pos,第三个是等待时间(单位秒)
selectmaster_pos_wait('mysql-bin.000017',25138958,5);
如果指定的pos值已经同步,改select将返回0,如果没有同步,将阻塞直到指定的时间,根据Exec_Master_Log_Pos的值可以判定同步的具体pos在哪,这样便能找到下一次同步的pos,通过slave上执行 
stopslave;
changemasterto master_log_pos=xxx;
startslave;
便能恢复数据同步。

接下来以经典的1236异常来说明怎么解决I/O的问题,1236问题并不是一个异常,而是一类异常,这类异常又有区分,不同的问题不同对待。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

1. Got fatal error 1236 from master when reading data from binary log: 'Client requested master to startreplicationfromposition > filesize'
这类异常最常见,触发的时机是主库在不断的数据入库,突然断电或强制重启,或强删(kill -9)导致主库binlog刷盘异常,从而使从库I/O线程读取到主库不存在的position,导致主从数据不一致。解决办法
从库执行show slave status; 查看Exec_Master_Log_Pos和Read_Master_Log_Pos已经不一致,通过mysqlbinlog查看主库的Relay_Master_Log_File文件,找到对应Exec_Master_Log_Pos相近的pos,这里有两种情况,一种是有相近的pos值,然后从库通过执行select master_pos_wait方式,查看已经同步的pos值,找到未同步的,然后从库执行 change master to master_log_pos=xxx;
另外一种情况就是Relay_Master_Log_File没有相近的pos值,这时候一般是本binlog已经完成同步,将master_log_file指向下一个文件,pos值改成下个文件的最小值即可。所以在配置主从时,为了减少此类事件的发生,设置sync_binlog=1最为靠谱,当然这是以牺牲性能为代价。
2. Got fatal error 1236 from master when reading data from binary log
这个时候需要注意,很有可能是主库的binlog已经被删除,从库无法从主库获取指定文件,这个只能在前期将expire_logs_days设置的较大些,例如180天,即6个月。
3. 从库的异常断电,强制重启,强删导致的relaylog刷盘异常
这类异常和主库binlog异常大同小异,为了防止此类事件的发生,建议设置sync_relay_log=1,这个意思是在从库读到binlog后,relaylog写入磁盘的频率,默认是1000,也就是当出现1000个事物事件后,从库才会执行fdatasync()此系统调用进行刷盘,1000之内的只是将数据写入文件缓存中依赖操作系统刷盘,但是设置的太小又会导致从库的I/O瓶颈,一直在刷盘,降低效率,所有需要综合考虑设置此值。
非主流的异常问题

myisam引擎表损坏导致的同步异常文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

笔者遇到过因为myisam表索引文件损坏,导致的异常,这类异常排查起来比较麻烦,解决确很容易,通过repair命令或者myisamchk工具将表文件修复,然后执行文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html

stop slave;
set global sql_slave_skip_counter=1;
start slave;
修复完把本次异常跳过即可。
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/sjk/23524.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/sjk/23524.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定