Andy Niu �����ĵ�

Andy Niu

Andy Niu Help  1.0.0.0
Mysql复制

变量

 主主复制的配置流程
 
 show_slave_status
 
 Mysql复制错误
 
 Reconnecting_after_a_failed_master_event_read
 
 Client_requested_master_to_start_replication_from_impossible_position
 
 半同步复制
 
 查看二进制日志
 

详细描述

变量说明

Client_requested_master_to_start_replication_from_impossible_position
1、错误如下:
    mysql> show slave status\G
    *************************** 1. row ***************************
                Slave_IO_State: 
                    Master_Host: 192.168.1.176
                    Master_User: root
                    Master_Port: 3306
                    Connect_Retry: 60
                Master_Log_File: mysql-bin.000010
            Read_Master_Log_Pos: 994941638
                Relay_Log_File: mysqld-relay-bin.000261
                    Relay_Log_Pos: 4
            Relay_Master_Log_File: mysql-bin.000010
                Slave_IO_Running: No
                Slave_SQL_Running: Yes
                Replicate_Do_DB: ibp
            Replicate_Ignore_DB: mysql
            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: 994941638
                Relay_Log_Space: 106
                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: NULL
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 1236
                    Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Client requested master to start replication from impossible position'
                Last_SQL_Errno: 0
                Last_SQL_Error: 
    1 row in set (0.00 sec)
2、从对方去复制一个不可能的位置,查看Master端的二进制日志,如下:
    [root@localhost mysql]# ll |grep mysql-bin.000010
    -rw-rw---- 1 mysql mysql  994934249 2015-12-03 16:27 mysql-bin.000010
3、也就是说,Slave去复制位置994941638,而Master端的位置只有994934249
4、查看Master端的错误日志,如下:
    InnoDB: Log scan progressed past the checkpoint lsn 0 670781756
    151204  9:12:26  InnoDB: Database was not shut down normally!
    InnoDB: Starting crash recovery.
    InnoDB: Reading tablespace information from the .ibd files...
    InnoDB: Restoring possible half-written data pages from the doublewrite
    InnoDB: buffer...
    InnoDB: Doing recovery: scanned up to log sequence number 0 671228026
    151204  9:12:26  InnoDB: Starting an apply batch of log records to the database...
    InnoDB: Progress in percents: 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
    40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 8
    1 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 
    InnoDB: Apply batch completed
    InnoDB: Last MySQL binlog file position 0 994941638, file name ./mysql-bin.000010
    151204  9:12:27  InnoDB: Started; log sequence number 0 671228026
    也就是说,Master端异常关闭,重启之后,进行崩溃恢复,而且也记录了崩溃前的二进制日志位置994941638,
    但是恢复之后,位置只有994934249,通过show binlog events 和 mysqlbinlog查看恢复后的日志文件,位置确实只到了994934249
5、也就是说,mysql异常关闭(直接断电),重启恢复二进制日志的时候出现错误,而Slave端还从旧的位置复制,出错。
    这个时候,两边的数据还是一致的。因为Master也写入数据库了,Slave端也复制了。
    只不过Master端恢复出现错误,同时Slave复制的位置没有了。
6、解决办法是,手工调整复制的文件和位置,从下一个文件的位置0开始。
7、异常关闭mysql(直接断电),除了会导致上面的问题。还会导致下面的问题:
    对于增删改操作,mysql记录二进制日志不会实时刷新到磁盘。通过sync_binlog可以设置刷新到磁盘的频率。
    为0,mysql不控制binlog的刷新,靠文件系统自己控制。
    大于0,mysql调用文件系统的刷新操作,刷新到磁盘。sync_binlog=1表示提交一次事务,就刷新。
    没有很好的理由,mysql建议不要修改sync_binlog的值,靠文件系统自己控制刷新。
    因为设置小了,导致频繁刷新到磁盘,性能很差。设置大了,刷新的延迟时间长,主从一致性的延迟也就大。
    那么问题来了:
    异常关闭mysql,可能出现数据已经修改了,但是二进制日志没有刷新到磁盘。这部分的修改没有发给Slave,主从不一致。
    对于这个问题,可以通过半同步复制来避免,但是这个要使用mysql5.5上面的一个插件,暂时不做了。
8、也就是说,根据mysql复制的实现原理,异常关闭mysql会导致一些问题,因此尽量避免直接断电关闭mysql,先正常关闭,再断电。
    如果出现了异常关闭,人工介入,进行调整。
Mysql复制错误
主备切换的流程:
1、hau彼此通信,初始化,认为当前设备是备机,收不到对方的消息,把自己切换为主机。
2、hau认为当前设备是备机,调用rpu_sdk的OnSlave,hau认为当前设备是主机,调用OnMaster
3、OnSlave做的事情:
    a、调用黄彪的脚本,禁用外网卡,删除外网卡的网关,同时把网关设置为对端内网ip
    b、把cmu,uac,uas,virgo等服务的可用状态设置为0,因为备机上的这些服务是不启动的。
        而dmu,vtdu要负载均衡,两边都可用,mysql,hau两边也都可用。
    c、然后关闭cmu,uac,uas,virgo,虽然guard是活着的,但是这些服务不可用,不会启动。
4、OnMaster做的事情:
    a、调用黄彪的脚本,激活外网卡,设置外网卡的网关,免费ARP,查询自身Ip地址对应的MAC地址,
        设置路由规则,对于出去的修改ip地址,发到外部,对于进来的,根据端口转发。
    b、所有服务的可用状态设置为1,guard会把它们启动。
经过反复测试,基本可以确定的是:
1、mysql正常的启动关闭,复制是不存在问题的。
2、对于目前的处理流程,正常的操作,复制是没有问题的。
问题是:
这两次出现的错误,错误码都是1236,就是Slave端的IO线程,从Master断读取二进制日志,出现错误。
1、第一次的错误信息是,Slave从Master读取一个不存在的问题
2、第二次的错误信息是,Master端的二进制日志被截断。

网上查了,基本上是出现这种问题,怎么解决?
出现这种情况,需要stop slave,需要使用change master to,修改Slave从Master复制的位置。然后start slave。

为什么出现这种情况?如何避免出现?
1、第一次的错误信息是,Slave从Master读取一个不存在的问题
    原因是:安装有问题,主主复制一端卸载又安装。比如A,B目前复制正常。A记到85位置,B也跟到85位置,A卸载,再安装。
    A安装的时候清除二进制日志,新的位置从0开始,而B还认为从85位置复制,出现错误,从一个不可能的位置复制。
2、第二次的错误信息是,Master端的二进制日志被截断。
    原因是:主库意外死机,导致binlog有问题。
注意:二进制日志,使用二进制格式保存,如果查看?
    需要使用程序 mysqlbinlog
Reconnecting_after_a_failed_master_event_read
1、rpu2000T 测试环境,mysql复制出现问题,如下:
    mysql> show slave status\G
    *************************** 1. row ***************************
                Slave_IO_State: Reconnecting after a failed master event read
                    Master_Host: 192.168.1.176
                    Master_User: root
                    Master_Port: 3306
                    Connect_Retry: 60
                Master_Log_File: mysql-bin.000003
            Read_Master_Log_Pos: 49136994
                Relay_Log_File: mysqld-relay-bin.000006
                    Relay_Log_Pos: 48636785
            Relay_Master_Log_File: mysql-bin.000003
                Slave_IO_Running: No
                Slave_SQL_Running: Yes
                Replicate_Do_DB: ibp
            Replicate_Ignore_DB: mysql
            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: 49136994
                Relay_Log_Space: 48637086
                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: NULL
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 2013
                    Last_IO_Error: error reconnecting to master '[email protected]:3306' - retry-time: 60  retries: 86400
                Last_SQL_Errno: 0
                Last_SQL_Error: 
    1 row in set (0.00 sec)
2、出现这种情况的原因是,对端作为master的mysql服务器关闭了,本地作为slave的mysql,读取二进制日志出现错误,然后会重连Master。
    重连间隔是60秒,重连86400次。
    注:在配置文件中,master-connect-retry重连间隔时间,master-retry-count重连次数
3、当对端的Master重新启动之后,slave重连成功,会接着读取二进制日志。
    这个场景,我已经模拟测试多次,是没有问题的。
4、现在的问题是,出现了一直重连不成功,我看到slave端的mysql错误日志如下:
    151124 15:05:05 [Note] Slave: received end packet from server, apparent master shutdown: 
    151124 15:05:05 [Note] Slave I/O thread: Failed reading log event, reconnecting to retry, log 'mysql-bin.000011' at position 
    37827
    151124 15:05:05 [ERROR] Slave I/O: error reconnecting to master '[email protected]:3306' - retry-time: 60  retries: 86400, E
    rror_code: 2013
    151124 15:06:05 [Note] Slave: connected to master '[email protected]:3306',replication resumed in log 'mysql-bin.000011' at 
    position 37827
    151125  9:35:26 [Note] Slave: received end packet from server, apparent master shutdown: 
    151125  9:35:26 [Note] Slave I/O thread: Failed reading log event, reconnecting to retry, log 'mysql-bin.000018' at position 
    6366231
    151125  9:35:26 [ERROR] Slave I/O: error reconnecting to master '[email protected]:3306' - retry-time: 60  retries: 86400, E
    rror_code: 2013
    151203 10:10:35 [Note] Error reading relay log event: slave SQL thread was killed
    在151124 15:05:05 对端的master关闭了,后面有重新连接成功,
    但是在151125 9:35:26 ,对端的master关闭了,后面没有重新连接成功,而且现在也没有超过重连次数,超过重连次数需要60*86400/86400=60天。
5、出现了这种情况,我通过在slave端执行 stop slave; 然后start slave,就可以了。但是为什么出现一直重连不上,原因还不清楚。
show_slave_status
Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.1.1.1
                  Master_User: rep_user
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: binlog.000026        从库I/O线程读取主库binlog文件名
          Read_Master_Log_Pos: 446                  从库I/O线程读取主库binlog的位置
               Relay_Log_File: relay.000008         从库SQL线程正在应用的relay-log文件名
                Relay_Log_Pos: 589                  从库SQL线程正在应用的relay-log位置
        Relay_Master_Log_File: binlog.000026        从库SQL线程正在应用的relay-log对应的binlog
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           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: 446                  从库SQL线程正在应用的relay-log对应binlog的位置
              Relay_Log_Space: 878
              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: 2211
 
可以这样理解:
1、从库I/O线程到主库中读取二进制文件,记录读取哪个二进制文件,以及读取到的位置。
2、从库I/O线程把读取到二进制内容,放入中继日志。
3、从库SQL线程重放中继日志,记录重放哪个中继日志,以及重放到中继日志的哪个位置。
    中继日志重放之后,产生一个位置,这个位置对应主库二进制的位置。
    中继日志的位置,和重放之后产生的位置(对应主库的二进制位置)完全不搭嘎。
4、这是典型的生产者/消费者模式,中继日志就是共享区,I/O往里面放,SQL从里面取。

Slave有两个线程:
1、I/O线程从Master接收二进制日志文件,写入本地的中继日志
2、SQL线程,读取中继日志,重放。典型的生产者/消费者模型

中继日志有三个位置:
1、中继日志的结尾,I/O从Master读到了哪个位置
2、SQL执行中继日志,执行到了哪个位置
3、重放之后,产生一个位置,这个位置对应Master上面的二进制文件位置。

Read_Master_Log_Pos与Master上面的show master status 位置相等,说明没有需要读取的内容,二者已经完全同步。
Read_Master_Log_Pos和Exec_Master_Log_Pos相等,说明没有需要重放的内容了。
要完全同步,满足两个条件:
1、Read_Master_Log_Pos与Master上面的show master status 位置相等,说明没有需要读取的内容。
2、Read_Master_Log_Pos和Exec_Master_Log_Pos相等,说明没有需要重放的内容了。

特别注意:Seconds_Behind_Master不是表示Slave比Master落后多少,而是对于SQL线程,中继日志中还有多少没有执行。
Seconds_Behind_Master=0 不表示Slave与Master完全同步,而是中继日志执行完了。
要判断是否完全同步,还需要判断Master记录到了哪个位置和Slave读到了哪个位置。

注:
1、二进制日志中,不包括数据查询语句。因为只是select,不会修改数据,因此不写入二进制日志。
2、在Master端,可以并行执行增删改操作,串行记录二进制日志。
    Slave端串行接收二进制日志,对于接收的二进制写入到中继日志。
    对于写入的中继日志,Slave只有一个SQL线程重放中继日志,不能并发执行,这往往会成为瓶颈。
主主复制的配置流程
1、先关闭B,把A的数据导出来,mysqldump -hlocalhost -uroot -p123456 ibprpu >ibprpu.sql
    注意:如果只导出表结构,使用 -d, --no-data       No row information. 详见mysqldump --help
2、关闭A,启动B,进入mysql建立一个新的数据库 create database ibprpu
3、导入数据库 mysql -hlocalhost -uroot -p123456 <ibprpu.sql,
    或者进入mysql,通过命令 source /root/ibprpu.sql 导入数据库
4、修改A和B的配置文件,my.cnf,重启A和B
5、注意:有些版本my.cnf中的复制属性配置不起作用,先关闭slave,再change master
6、stop slave; 
    change master to master_host='192.168.1.101',master_port=3306,master_user='root',master_password='123456';
    必要的时候还需要指定master_log_file 和 master_log_pos。
7、Last_IO_Errno: 1236 错误的原因是 从master读取一个无效的位置,在主机上执行 show master status 查看二进制日志的位置,
    在备机上,关闭slave,change master 重新指定master_log_pos。
    如果还有错误,stop slave; set global sql_slave_skip_counter=1; start slave;
8、主机要记录二进制日志,配置如下:
    log-bin=mysql-bin
    这种情况下,查询mysql的版本,后面带有log,如下
    mysql> select version();
    +------------+
    | version()  |
    +------------+
    | 5.1.66-log |
    +------------+
半同步复制
1、mysql的复制是异步的,也就是说,Master提交事务后,写入二进制日志(可能还没有刷新到磁盘),然后成功返回给客户端。
    并不等待二进制日志传送给Slave。
2、考虑下面的极端情况,Master提交事务,写入二进制日志(可能还没有刷新到磁盘),这个时候主库宕机,磁盘故障或者内存故障,
    导致这个事务丢失,Slave损失这个事务,主从不一致。
3、怎么解决这个问题?
    Master提交事务,写入二进制日志时,并不及时回复客户端成功,而是等待这个事务的二进制日志成功发给Slave,回复客户端成功。
    这样就保证了两份日志记录,一份在Master的二进制日志,一份在Slave的中继日志。这就是半同步复制。
4、为什么叫半同步复制?
    如果要完全同步复制,需要Master提交事务,写入二进制日志,成功发给Slave,Slave的SQL线程执行完毕,两边的数据一致,再回复给客户端。
    但是这里,只是成功发给了Slave,Slave还没有执行,数据还不一致,只要执行了,理论上是一致的。因此叫半同步复制。
5、注意:二进制日志,mysql不会删除,因为可能好几天之后在配置Slave去复制,因此最早的二进制日志也要保存。
    需要手工处理二进制日志。对于中继日志,mysql会定时清除,它只是复制过来,然后执行。
查看二进制日志
1、使用mysqlbinlog程序,mysqlbinlog --help 或者 mysqlbinlog -? 查看帮助文档。
    注意:如果是binlog格式是ROW,使用mysqlbinlog查看会是乱码,此时需要使用选项 -vv --base64-output=decode-rows
2、mysql登录之后,使用语法 show binlog events in 'mysql-bin.000010' limit 10,2\G
    help show binlog events; 查看帮助文档
3、注意:使用mysqlbinlog,--start-position必须是二进制日志中存在的位置,这个位置就是字节个数,如下:
    [root@localhost mysql]# mysqlbinlog mysql-bin.000010 --start-position=994934222 -vv --base64-output=decode-rows
    /*!40019 SET @@session.max_insert_delayed_threads=0*/;
    /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
    DELIMITER /*!*/;
    # at 994934222
    #151203  3:03:39 server id 213  end_log_pos 994934249   Xid = 4154885
    COMMIT/*!*/;
    DELIMITER ;
    # End of log file
    ROLLBACK /* added by mysqlbinlog */;
    /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
    如果使用了没有存在的位置,报错如下:
    [root@localhost mysql]# mysqlbinlog mysql-bin.000010 --start-position=994934221 -vv --base64-output=decode-rows
    /*!40019 SET @@session.max_insert_delayed_threads=0*/;
    /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
    DELIMITER /*!*/;
    ERROR: Error in Log_event::read_log_event(): 'read error', data_len: 6912, event_type: 86
    DELIMITER ;
    # End of log file
    ROLLBACK /* added by mysqlbinlog */;
    /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
4、那么问题来了,如果不知道位置怎么办?
5、可以先使用show binlog events找到位置,show binlog events in 'mysql-bin.000010' limit 0,2 中的limit是指操作的个数。
    mysql> show binlog events in 'mysql-bin.000010' limit 5092175,10\G
    *************************** 1. row ***************************
    Log_name: mysql-bin.000010
            Pos: 994933417
    Event_type: Query
    Server_id: 213
    End_log_pos: 994933547
        Info: use `ibp`; delete from dev_accesory where DEVID= NAME_CONST('_devid',1867)
    *************************** 2. row ***************************
    Log_name: mysql-bin.000010
            Pos: 994933547
    Event_type: Xid
    Server_id: 213
    End_log_pos: 994933574
        Info: COMMIT /* xid=4154883 */
    *************************** 3. row ***************************
    Log_name: mysql-bin.000010
            Pos: 994933574
    Event_type: Query
    Server_id: 213
    End_log_pos: 994933646
        Info: BEGIN
    *************************** 4. row ***************************
    Log_name: mysql-bin.000010
            Pos: 994933646
    Event_type: Query
    Server_id: 213
    End_log_pos: 994934222
        Info: use `ibp`; insert into dev_accesory(DEVID,LOCATIONTYPEID,DESCRIPTION,MODEL,INSTALLSPOT,INSTALLTIME,CONTRACTOR,MAINTAINER,PHONE,VISIBLE,LONGITUDE,LATITUDE,FAST,UPDATETIME) 
                    values( NAME_CONST('_devid',1867), NAME_CONST('_lid',0), NAME_CONST('_desc',NULL), NAME_CONST('_mod',NULL), NAME_CONST('_inspot',NULL), NAME_CONST('_iname',NULL), NAME_CONST('_con',NULL), NAME_CONST('_mant',NULL), NAME_CONST('_phone',NULL), NAME_CONST('_vis',1), NAME_CONST('_longt',0), NAME_CONST('_latt',0), NAME_CONST('_fast',0),now())
    *************************** 5. row ***************************
    Log_name: mysql-bin.000010
            Pos: 994934222
    Event_type: Xid
    Server_id: 213
    End_log_pos: 994934249
        Info: COMMIT /* xid=4154885 */
    5 rows in set (4.81 sec)
    注意:一个增删改操作或者事物,分为3个操作,一个BEGIN,一个执行sql语句,一个COMMIT
6、二进制日志中的位置就是文件大小,多少个字节数,需要注意的是:文件大小是最后一个操作的end_log_pos,如下:
    [root@localhost mysql]# ll |grep mysql-bin.000010
    -rw-rw---- 1 mysql mysql  994934249 2015-12-03 16:27 mysql-bin.000010
    
    [root@localhost mysql]# mysqlbinlog mysql-bin.000010 --start-position=994934222 -vv --base64-output=decode-rows
    /*!40019 SET @@session.max_insert_delayed_threads=0*/;
    /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
    DELIMITER /*!*/;
    # at 994934222
    #151203  3:03:39 server id 213  end_log_pos 994934249   Xid = 4154885
    COMMIT/*!*/;
    DELIMITER ;
    # End of log file
    ROLLBACK /* added by mysqlbinlog */;
    /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
Copyright (c) 2015~2016, Andy Niu @All rights reserved. By Andy Niu Edit.