当前位置:Gxlcms > 数据库问题 > Slave SQL_THREAD如何重放Relay log

Slave SQL_THREAD如何重放Relay log

时间:2021-07-01 10:21:17 帮助过:6人阅读

   优点:

    1)Binlog文件较小

    2)日志是包含用户执行的原始SQL,方便统计和审计

    3)出现最早binlog兼容较好

    4)Binlog方便阅读,方便故障修复

   缺点:

   1)存在安全隐患,可能导致主从数据不一致

   2)对一些系统函数不能准复制或是不能复制,例如

       Load_file()

       uuid()

       User()

       Found_rows()

       Sysdate()

 

Row格式(记录了行的修改情况):

    优点:

     1)相比Statement更安全的复制格式

     2)在某些情况下复制速度更快(SQL复杂,表有主键的时候)

     3)系统的特殊函数也可以复制

     4)更少的锁

    缺点:

     1)Binary log比较大 (mysql-5.6支持binlog_row_image)

   2)单语句更新或者删除表的行数过多,会形成大量binlog

     3)无法从Binlog看见用户执行的SQL (mysql-5.6增加了一个新的Event: binlog_row_query_log_events,记录用户的query)

 

MIXED格式:

    1)混合使用ROW和STATEMENT模式。对于DDL记录会STATEMENT,

    2)如果使用innodb表,事务级别使用了READ COMMITED 或READ UNCOMMITTED日志级别只能使用Row格式

    3)但在使用ROW格式中的DDL语句还是会记录来STATEMENT格式

    4)MIXED模式,那么在以下几种情况下会自动将binlog的模式,由SBR模式改成RBR模式。

        1、当DML语句更新一个NDB表时

        2、当函数中包含UUID()时

        3、2个及以上包含AUTO_INCREMENT字段的表被更新时

        4、任何INSERT DELAYED语句时

        5、用UDF时

        6、视图中必须要求使用RBR时,例如创建视图是使用了UUID()函数

 

下面我们看幅图,再进行举例子说明:(基于ROW格式的复制流程)

 技术分享

 

 

针对这个图,我们以下进行这四种测试:

一、表有主键索引

二、表有唯一键索引

三、表有普通索引

四、表没有任何索引

 

 

 

 测试一:表有主键

在Master上创建tb1表,有主键:

<master>(root@localhost) [xuanzhi]> SHOW variables like binlog_format;
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.00 sec)

<master>(root@localhost) [xuanzhi]> show create table tb1\G             
*************************** 1. row ***************************
       Table: tb1
Create Table: CREATE TABLE `tb1` (
  `id` int(11) NOT NULL,
  `name` varchar(20) NOT NULL,
  `age` tinyint(4) NOT NULL,
  `sex` tinyint(4) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

<master>(root@localhost) [xuanzhi]> select * from tb1;
+----+--------+-----+-----+
| id | name   | age | sex |
+----+--------+-----+-----+
| 10 | innodb |  20 |   0 |
| 20 | myisam |  22 |   1 |
| 30 | memory |  22 |   1 |
| 40 | redis  |  32 |   0 |
| 50 | codis  |  30 |   1 |
+----+--------+-----+-----+
5 rows in set (0.00 sec)

<master>(root@localhost) [xuanzhi]> 

在slave上模拟数据不一致,把第一条数据修改下:

Database changed
<slave>(root@localhost) [xuanzhi]> select * from tb1;
+----+--------+-----+-----+
| id | name   | age | sex |
+----+--------+-----+-----+
| 10 | innodb |  20 |   0 |
| 20 | myisam |  22 |   1 |
| 30 | memory |  22 |   1 |
| 40 | redis  |  32 |   0 |
| 50 | codis  |  30 |   1 |
+----+--------+-----+-----+
5 rows in set (0.00 sec)

<slave>(root@localhost) [xuanzhi]> update  tb1 set name=innosql where id=10;     
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

<slave>(root@localhost) [xuanzhi]> select * from tb1;                              
+----+---------+-----+-----+
| id | name    | age | sex |
+----+---------+-----+-----+
| 10 | innosql |  20 |   0 |
| 20 | myisam  |  22 |   1 |
| 30 | memory  |  22 |   1 |
| 40 | redis   |  32 |   0 |
| 50 | codis   |  30 |   1 |
+----+---------+-----+-----+
5 rows in set (0.00 sec)

<slave>(root@localhost) [xuanzhi]> 

这时主从数据已经不一致了,在master执行update操作会不会报1032没有找到记录的错误呢,我们试试:

<master>(root@localhost) [xuanzhi]> update tb1 set name=oracle where id=10;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

<master>(root@localhost) [xuanzhi]> 

回Slave库上查看同步是否有问题:

<slave>(root@localhost) [xuanzhi]> select * from tb1 where id=10;
+----+--------+-----+-----+
| id | name   | age | sex |
+----+--------+-----+-----+
| 10 | oracle |  20 |   0 |
+----+--------+-----+-----+
1 row in set (0.00 sec)

<slave>(root@localhost) [xuanzhi]> show slave status\G                        
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.10.132
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000012
          Read_Master_Log_Pos: 1632
               Relay_Log_File: localhost-relay-bin.000005
                Relay_Log_Pos: 1778
        Relay_Master_Log_File: mysql-bin.000012
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

可以看到数据是正常复制的,而且同步没有断开。

 

测试二:有唯一索引

查看表结构,在id列上是有唯一索引的:

<master>(root@localhost) [xuanzhi]> show create table tb1\G
*************************** 1. row ***************************
       Table: tb1
Create Table: CREATE TABLE `tb1` (
  `id` int(11) NOT NULL,
  `name` varchar(20) NOT NULL,
  `age` tinyint(4) NOT NULL,
  `sex` tinyint(4) NOT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

<master>(root@localhost) [xuanzhi]> 

在从库修改一行数据,模拟数据不一致:

<slave>(root@localhost) [xuanzhi]> select * from tb1;
+----+--------+-----+-----+
| id | name   | age | sex |
+----+--------+-----+-----+
| 10 | oracle |  20 |   0 |
| 20 | myisam |  22 |   1 |
| 30 | memory |  22 |   1 |
| 40 | redis  |  32 |   0 |
| 50 | codis  |  30 |   1 |
+----+--------+-----+-----+
5 rows in set (0.00 sec)

<slave>(root@localhost) [xuanzhi]> update tb1 set name=python where id=10;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

<slave>(root@localhost) [xuanzhi]> select * from tb1 where id=10;
+----+--------+-----+-----+
| id | name   | age | sex |
+----+--------+-----+-----+
| 10 | python |  20 |   0 |
+----+--------+-----+-----+
1 row in set (0.00 sec)

<slave>(root@localhost) [xuanzhi]> 

在Master进行update操作:

<master>(root@localhost) [xuanzhi]> select * from tb1 where id=10;
+----+--------+-----+-----+
| id | name   | age | sex |
+----+--------+-----+-----+
| 10 | oracle |  20 |   0 |
+----+--------+-----+-----+
1 row in set (0.00 sec)

<master>(root@localhost) [xuanzhi]> update tb1 set name=java where id=10;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

<master>(root@localhost) [xuanzhi]> 

回slave库查看是否出现主从断开的可能:

<slave>(root@localhost) [xuanzhi]> select * from tb1 where id=10;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 10 | java |  20 |   0 |
+----+------+-----+-----+
1 row in set (0.00 sec)

<slave>(root@localhost) [xuanzhi]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.10.132
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000012
          Read_Master_Log_Pos: 2035
               Relay_Log_File: localhost-relay-bin.000005
                Relay_Log_Pos: 2181
        Relay_Master_Log_File: mysql-bin.000012
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

可以看到当主从数据不一到的时候,基于唯一键更新,同步也是正常的,数据也是同步过来的。

 

测试三:当表只有普通索引

在master上看到表只有普通索引:

<master>(root@localhost) [xuanzhi]> show create table tb1\G
*************************** 1. row ***************************
       Table: tb1
Create Table: CREATE TABLE `tb1` (
  `id` int(11) NOT NULL,
  `name` varchar(20) NOT NULL,
  `age` tinyint(4) NOT NULL,
  `sex` tinyint(4) NOT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

<master>(root@localhost) [xuanzhi]> 

在slave库上模拟数据不一致的情况:

<slave>(root@localhost) [xuanzhi]> update tb1 set name=php where id=10;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

<slave>(root@localhost) [xuanzhi]> select * from tb1 where id=10;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 10 | php  |  20 |   0 |
+----+------+-----+-----+
1 row in set (0.00 sec)

<slave>(root@localhost) [xuanzhi]>

回到master更新一条记录看看:

<master>(root@localhost) [xuanzhi]> select * from tb1 where id=10;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 10 | java |  20 |   0 |
+----+------+-----+-----+
1 row in set (0.00 sec)

<master>(root@localhost) [xuanzhi]> update tb1 set name=nosql where id=10;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

<master>(root@localhost) [xuanzhi]> 
<slave>(root@localhost) [xuanzhi]> select * from tb1 where id=10;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 10 | php  |  20 |   0 |
+----+------+-----+-----+
1 row in set (0.00 sec)

<slave>(root@localhost) [xuanzhi]> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.10.132
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000012
          Read_Master_Log_Pos: 2426
               Relay_Log_File: localhost-relay-bin.000005
                Relay_Log_Pos: 2369
        Relay_Master_Log_File: mysql-bin.000012
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 1032
                   Last_Error: Could not execute Update_rows event on table xuanzhi.tb1; Cant find record in tb1, Error_code: 1032; handler error HA_ERR_END_OF_FILE; the events master log mysql-bin.000012, end_log_pos 2399

 我们查看一下Binlog做了什么操作:

技术分享
[root@localhost ~]#  mysqlbinlog  -v --base64-output=DECODE-ROWS  --start-position=2223 --stop-position=2399 /data/mysql/data/mysql-bin.000012
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 2223
#150626  9:12:20 server id 1  end_log_pos 2294  Query   thread_id=14    exec_time=0     error_code=0
SET TIMESTAMP=1435281140/*!*/;
SET @@session.pseudo_thread_id=14/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
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=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 2294
# at 2344
#150626  9:12:20 server id 1  end_log_pos 2344  Table_map: `xuanzhi`.`tb1` mapped to number 45
#150626  9:12:20 server id 1  end_log_pos 2399  Update_rows: table id 45 flags: STMT_END_F
### UPDATE xuanzhi.tb1
### WHERE
###   @1=10
###   @2=java
###   @3=20
###   @4=0
### SET
###   @1=10
###   @2=nosql
###   @3=20
###   @4=0
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
[root@localhost ~]# 
View Code

可以看到,update语句执行的条件大致是这样的:where id=xx and name=xx and age=xx and sex=xx,当这条语句在slave上被执行时,slave库上发现id=10 name=java...这条记录不存在,所以报了1032错误。(后来我看了有主键和唯一索引的binlog日志信息,也是跟普通索引一样的,只是有主键的和唯一索引的时候不会把这条记录的数据都检查一遍)

 

测试四:表没有索引

在master查看表结构,表是没有索引的:

<master>(root@localhost) [xuanzhi]> show create table tb1\G     
*************************** 1. row ***************************
       Table: tb1
Create Table: CREATE 

                  

	 	
                    
                    
                    
                    
                    
                

人气教程排行