MySQL複製之深入理解binlog_format及表字段順序的重要性

我們知道binlog的格式有rbr,sbr還有mbr。

mbr不需多說,就是優先sbr,實在不行就rbr。

那麼sbr怎麼理解?根據文檔來看,就是master端將執行的sql語句直接寫入binlog裏。slave端在重演時也執行一遍這些sql語句。

這就是sbr的意思。

聽起來好像sbr真的能100%保證master和slave一致?

那可不一定了!

比如我們在master端執行如下sql:

mysql> set @@session.binlog_format=statement;
Query OK, 0 rows affected (0.00 sec)


mysql> insert into t2(uid) values(uuid());
Query OK, 1 row affected, 1 warning (0.28 sec)


mysql> select * from t2;
+----+--------------------------------------+
| id | uid                                  |
+----+--------------------------------------+
|  1 | 602d9a9d-f187-11e5-a634-5c260a17ccde |
+----+--------------------------------------+
1 rows in set (0.00 sec)


mysql>

而在slave端,我們查詢t2表時,發現:

mysql> select * from t2;
+----+--------------------------------------+
| id | uid                                  |
+----+--------------------------------------+
|  1 | 60549b1b-f187-11e5-803d-5c260a17ccde |
+----+--------------------------------------+
1 rows in set (0.00 sec)


mysql>

你看,紅色部分表示master端和slave的uid值明顯不一致。

所以很容易得出結論,sbr的binlog的複製環境是不安全,無法保證100%的數據一致性。


由於sbr是master端將sql語句寫入binlog文件,而不管這個語句是否在master端引起更改。所以slave端接收到的event也是sql語句。

也就是說,在sbr裏,master端執行了什麼樣子的sql語句,那麼在slave端也要執行同樣的SQL語句。

這就會有一個現象是,同一個語句在master沒有引起更改,而在slave重演時引起了更改。或者兩端都引起了更改,但是兩端的更改不一致。


而rbr呢?

在rbr中,如果一個語句在master沒有引起更改,那麼這個語句是不會被binlog的。也就是說這個語句不會被重演到slave端。

什麼樣的語句是不會引起更改的語句?比如:

mysql> SELECT * FROM t1;
+----+------+-------+
| id | name | score |
+----+------+-------+
|  1 | za   |    12 |
|  2 | za   |    13 |
|  3 | za   |    19 |
|  4 | za   |    50 |
|  5 | zb   |     9 |
|  6 | zb   |    89 |
|  7 | zb   |    90 |
+----+------+-------+
7 rows in set (0.00 sec)


mysql> UPDATE t1
    -> SET t1.`score`=12
    -> WHERE t1.`id`=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0


mysql>

我們試圖更改的行,更改前和更改後是一致的。所以Changed: 0  。

這條語句在rbr模式下,就不會被binlog,也就不會被重演到slave端。因爲他並沒有引起行更改。

我們繼續討論rbr較sbr的複製安全性問題,請看:

在master端

mysql> set @@session.binlog_format=row;
Query OK, 0 rows affected (0.00 sec)


mysql> use test
Database changed
mysql> truncate table t2;
Query OK, 0 rows affected (0.29 sec)


mysql> insert into t2(uid) values(uuid());
Query OK, 1 row affected (0.34 sec)


mysql> select * from t2;
+----+--------------------------------------+
| id | uid                                  |
+----+--------------------------------------+
|  1 | f130ebcb-f187-11e5-a634-5c260a17ccde |
+----+--------------------------------------+
1 row in set (0.00 sec)


mysql>

而我們查詢下slave端的數據:

mysql> use test
Database changed
mysql> select * from t2;
Empty set (0.00 sec)


mysql> select * from t2;
+----+--------------------------------------+
| id | uid                                  |
+----+--------------------------------------+
|  1 | f130ebcb-f187-11e5-a634-5c260a17ccde |
+----+--------------------------------------+
1 row in set (0.00 sec)


mysql>

根據紅色部分,我們得出,基於rbr的複製是安全的。


但是rbr的複製真的就那麼安全嗎?

答案是:呵呵。

爲什麼是呵呵呢,請往下面繼續看。

我們假設這麼一個場景,小張是dba,應開發人員小王的要求在生產庫的master端建了表t1:



C:\>mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.11-log MySQL Community Server (GPL)


Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.


Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.


Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


mysql> select @@session.binlog_format;
+-------------------------+
| @@session.binlog_format |
+-------------------------+
| STATEMENT               |
+-------------------------+
1 row in set (0.00 sec)


mysql> set @@session.binlog_format=row;
Query OK, 0 rows affected (0.00 sec)


mysql> drop table if exists t1;
ERROR 1046 (3D000): No database selected
mysql> use test
Database changed
mysql> drop table if exists t1;
Query OK, 0 rows affected (0.23 sec)


mysql> CREATE TABLE t1 (
    ->   id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->   a VARCHAR (5),
    ->   b VARCHAR (5),
    ->   c VARCHAR (5),
    ->   d VARCHAR (5)
    -> );
Query OK, 0 rows affected (0.29 sec)


mysql> desc t1;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | int(11)    | NO   | PRI | NULL    | auto_increment |
| a     | varchar(5) | YES  |     | NULL    |                |
| b     | varchar(5) | YES  |     | NULL    |                |
| c     | varchar(5) | YES  |     | NULL    |                |
| d     | varchar(5) | YES  |     | NULL    |                |
+-------+------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)


mysql>

這個表很明顯,正確地被複制到了slave端:

mysql> use test
Database changed
mysql> desc t1;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | int(11)    | NO   | PRI | NULL    | auto_increment |
| a     | varchar(5) | YES  |     | NULL    |                |
| b     | varchar(5) | YES  |     | NULL    |                |
| c     | varchar(5) | YES  |     | NULL    |                |
| d     | varchar(5) | YES  |     | NULL    |                |
+-------+------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)


mysql>

然後小王很高興地往t1表裏插入若干條數據,當然這發生在master端:

mysql> use test;
Database changed

mysql> select @@session.binlog_format;
+-------------------------+
| @@session.binlog_format |
+-------------------------+
| ROW                        |
+-------------------------+
1 row in set (0.00 sec)

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES('a1','b2','c3','d4');
Query OK, 1 row affected (0.11 sec)


mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES('a11','b22','c33','d44');
Query OK, 1 row affected (0.10 sec)


mysql> select * from t1;
+----+------+------+------+------+
| id | a    | b    | c    | d    |
+----+------+------+------+------+
|  1 | a1   | b2   | c3   | d4   |
|  2 | a11  | b22  | c33  | d44  |
+----+------+------+------+------+
2 rows in set (0.00 sec)


mysql>

很明顯,這也被正確地複製到了slave端:

mysql> select * from t1;
+----+------+------+------+------+
| id | a    | b    | c    | d    |
+----+------+------+------+------+
|  1 | a1   | b2   | c3   | d4   |
|  2 | a11  | b22  | c33  | d44  |
+----+------+------+------+------+
2 rows in set (0.00 sec)


mysql>


但是,但是,有天dba小張在維護slave數據庫時不小心把t1表的字段順序調整了,注意是slave端的操作:

mysql> ALTER TABLE `test`.`t1`
    ->   CHANGE `d` `d` VARCHAR(5) CHARSET utf8 COLLATE utf8_general_ci NULL  AFTER `a`,
    ->   CHANGE `c` `c` VARCHAR(5) CHARSET utf8 COLLATE utf8_general_ci NULL  AFTER `d`,
    ->   CHANGE `b` `b` VARCHAR(5) CHARSET utf8 COLLATE utf8_general_ci NULL  AFTER `c`;
Query OK, 0 rows affected (0.56 sec)
Records: 0  Duplicates: 0  Warnings: 0


mysql> select * from t1;
+----+------+------+------+------+
| id | a    | d    | c    | b    |
+----+------+------+------+------+
|  1 | a1   | d4   | c3   | b2   |
|  2 | a11  | d44  | c33  | b22  |
+----+------+------+------+------+
2 rows in set (0.00 sec)


mysql>

注意字段順序由a,b,c,d變成了a,d,c,b。


ok,你認爲此時複製會不會失敗?會嗎?

來看看,小王繼續在mater端插入數據:

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES('a111','b222','c333','d444');
Query OK, 1 row affected (0.09 sec)


mysql> select * from t1;
+----+------+------+------+------+
| id | a    | b    | c    | d    |
+----+------+------+------+------+
|  1 | a1   | b2   | c3   | d4   |
|  2 | a11  | b22  | c33  | d44  |
|  3 | a111 | b222 | c333 | d444 |
+----+------+------+------+------+
3 rows in set (0.00 sec)


mysql>

而slave端的複製狀態呢?失敗了嗎?我們看看狀態:

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.77
                  Master_User: backup
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000035
          Read_Master_Log_Pos: 4265
               Relay_Log_File: host_name-relay-bin.000016
                Relay_Log_Pos: 4478
        Relay_Master_Log_File: mysql-bin.000035
             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: 4265
              Relay_Log_Space: 6875
              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_UUID: e2e2f927-e75c-11e5-ac89-5c260a17ccde
             Master_Info_File: mysql.slave_master_info
                    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: e2e2f927-e75c-11e5-ac89-5c260a17ccde:7371-7396
            Executed_Gtid_Set: 1cced57b-e75e-11e5-b742-5c260a17ccde:1-24,
e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7396

                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)


mysql>

我靠,複製正常進行,沒有出錯。我們來看看slave端t1表的數據:

mysql> select a,b,c,d from t1;
+------+------+------+------+
| a    | b    | c    | d    |
+------+------+------+------+
| a1   | b2   | c3   | d4   |
| a11  | b22  | c33  | d44  |
| a111 | d444 | c333 | b222 |
+------+------+------+------+
3 rows in set (0.00 sec)


mysql>

mysql> select * from t1;
+----+------+------+------+------+
| id | a    | d    | c    | b    |
+----+------+------+------+------+
|  1 | a1   | d4   | c3   | b2   |
|  2 | a11  | d44  | c33  | b22  |
|  3 | a111 | b222 | c333 | d444 |
+----+------+------+------+------+
3 rows in set (0.00 sec)


mysql>

尼瑪,啥情況?小王在master插入的數據明明是a=a111,b=b222,c=c333,d=d444.

但是被複制到slave端之後,變成了a=a111,b=d444,c=c333,d=b222。


呵呵,rbr複製出錯了。有木有?

你可能會覺得,不是rbr複製出錯,而是小張偷偷地調整了t1表的字段順序導致的。

嗯,的確也是這樣。由於slave端的表結構字段順序變了,所以複製實際上已經出錯了。

這就是爲什麼mysql數據庫的表的字段順序很重要的原因。


那麼,我們回過頭來猜猜,在master端和slave端字段順序不同的情況下,sbr能不能保證正確複製呢?繼續看

mysql> set @@session.binlog_format=statement;
Query OK, 0 rows affected (0.00 sec)


mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES('a1111','b2222','c3333','d4444');
Query OK, 1 row affected (0.35 sec)


mysql> select a,b,c,d from t1;
+-------+-------+-------+-------+
| a     | b     | c     | d     |
+-------+-------+-------+-------+
| a1    | b2    | c3    | d4    |
| a11   | b22   | c33   | d44   |
| a111  | b222  | c333  | d444  |
| a1111 | b2222 | c3333 | d4444 |
+-------+-------+-------+-------+
4 rows in set (0.00 sec)


mysql>

而在slave端我們看看結果:

mysql> select a,b,c,d from t1;
+-------+-------+-------+-------+
| a     | b     | c     | d     |
+-------+-------+-------+-------+
| a1    | b2    | c3    | d4    |
| a11   | b22   | c33   | d44   |
| a111  | d444  | c333  | b222  |
| a1111 | b2222 | c3333 | d4444 |
+-------+-------+-------+-------+
4 rows in set (0.00 sec)


mysql> select * from t1;
+----+-------+-------+-------+-------+
| id | a     | d     | c     | b     |
+----+-------+-------+-------+-------+
|  1 | a1    | d4    | c3    | b2    |
|  2 | a11   | d44   | c33   | b22   |
|  3 | a111  | b222  | c333  | d444  |
|  4 | a1111 | d4444 | c3333 | b2222 |
+----+-------+-------+-------+-------+
4 rows in set (0.00 sec)


mysql>

記錄被正確複製,有木有?答案是有的。


因爲sbr是將sql語句原封不動地寫入binlog文件(所以被原封不動地重演到slave端)。但是rbr呢?

我們可以使用工具mysqlbinlog來看看binlog文件就知道了:

mysql> flush logs;
Query OK, 0 rows affected (0.30 sec)


mysql> show master status\g
+------------------+----------+--------------+------------------+---------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                           |
+------------------+----------+--------------+------------------+---------------------------------------------+
| mysql-bin.000036 |      194 |              |                  | e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7397 |
+------------------+----------+--------------+------------------+---------------------------------------------+
1 row in set (0.00 sec)


mysql>

切換到新的binlog文件上,並且當前binlog是36號文件。

在sbr模式下:

mysql> set @session.binlog_format='statement';
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES('az','bz','cz','dz');
Query OK, 1 row affected (0.07 sec)


mysql> flush logs;
Query OK, 0 rows affected (0.30 sec)


mysql>

我們看看36號binlog文件:

D:\Program Files\mysql-5.7.11-winx64\data>mysqlbinlog -v mysql-bin.000036
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#160324 14:43:24 server id 2  end_log_pos 123 CRC32 0x5f231a1b  Start: binlog v 4, server v 5.7.11-log created 160324 14:43:24
BINLOG '
jIzzVg8CAAAAdwAAAHsAAAAAAAQANS43LjExLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
ARsaI18=
'/*!*/;
# at 123
#160324 14:43:24 server id 2  end_log_pos 194 CRC32 0xf8ccad7f  Previous-GTIDs
# e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7397
# at 194
#160324 14:45:31 server id 2  end_log_pos 259 CRC32 0x1d072fcf  GTID    last_committed=0        sequence_number=1
SET @@SESSION.GTID_NEXT= 'e2e2f927-e75c-11e5-ac89-5c260a17ccde:7398'/*!*/;
# at 259
#160324 14:45:31 server id 2  end_log_pos 338 CRC32 0x68889415  Query   thread_id=8     exec_time=0 error_code=0
SET TIMESTAMP=1458801931/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
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=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 338
# at 370
#160324 14:45:31 server id 2  end_log_pos 370 CRC32 0x63a4e5cb  Intvar
SET INSERT_ID=5/*!*/;
#160324 14:45:31 server id 2  end_log_pos 516 CRC32 0xeba65974  Query   thread_id=8     exec_time=0 error_code=0
use `test`/*!*/;
SET TIMESTAMP=1458801931/*!*/;
INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES('az','bz','cz','dz')
/*!*/;
# at 516
#160324 14:45:31 server id 2  end_log_pos 547 CRC32 0x233469fc  Xid = 88
COMMIT/*!*/;
# at 547
#160324 14:45:40 server id 2  end_log_pos 594 CRC32 0xc96a01d9  Rotate to mysql-bin.000037  pos: 4
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*/;


D:\Program Files\mysql-5.7.11-winx64\data>

看到有木有?sbr模式下是將sql語句直接寫入binlog文件的。


那麼rbr呢?繼續看

mysql> show master status\G
*************************** 1. row ***************************
             File: mysql-bin.000037
         Position: 194
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set: e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7398
1 row in set (0.00 sec)


mysql> set @@session.binlog_format='row';
Query OK, 0 rows affected (0.00 sec)


mysql> INSERT INTO `test`.`t1` (`a`, `b`, `c`, `d`) VALUES('azz','bzz','czz','dzz');
Query OK, 1 row affected (0.13 sec)


mysql> flush logs;
Query OK, 0 rows affected (0.30 sec)


mysql>

我們打開37號binlog文件:

D:\Program Files\mysql-5.7.11-winx64\data>mysqlbinlog -v mysql-bin.000037
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#160324 14:45:40 server id 2  end_log_pos 123 CRC32 0x81532d9a  Start: binlog v 4, server v 5.7.11-log created 160324 14:45:40
BINLOG '
FI3zVg8CAAAAdwAAAHsAAAAAAAQANS43LjExLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
AZotU4E=
'/*!*/;
# at 123
#160324 14:45:40 server id 2  end_log_pos 194 CRC32 0xbcc90ada  Previous-GTIDs
# e2e2f927-e75c-11e5-ac89-5c260a17ccde:1-7398
# at 194
#160324 14:49:17 server id 2  end_log_pos 259 CRC32 0xf703e1df  GTID    last_committed=0        sequence_number=1
SET @@SESSION.GTID_NEXT= 'e2e2f927-e75c-11e5-ac89-5c260a17ccde:7399'/*!*/;
# at 259
#160324 14:49:17 server id 2  end_log_pos 331 CRC32 0xc0d13c56  Query   thread_id=8     exec_time=0 error_code=0
SET TIMESTAMP=1458802157/*!*/;
SET @@session.pseudo_thread_id=8/*!*/;
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=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 331
#160324 14:49:17 server id 2  end_log_pos 388 CRC32 0x5956c1fb  Table_map: `test`.`t1` mapped to number 112
# at 388
#160324 14:49:17 server id 2  end_log_pos 444 CRC32 0x42c7621a  Write_rows: table id 112 flags: STMT_END_F


BINLOG '
7Y3zVhMCAAAAOQAAAIQBAAAAAHAAAAAAAAEABHRlc3QAAnQxAAUDDw8PDwgPAA8ADwAPAB77wVZZ
7Y3zVh4CAAAAOAAAALwBAAAAAHAAAAAAAAEAAgAF/+AGAAAAA2F6egNienoDY3p6A2R6ehpix0I=
'
/*!*/;
### INSERT INTO `test`.`t1`
### SET
###   @1=6
###   @2='azz'
###   @3='bzz'
###   @4='czz'
###   @5='dzz'

# at 444
#160324 14:49:17 server id 2  end_log_pos 475 CRC32 0x7cd4b94a  Xid = 92
COMMIT/*!*/;
# at 475
#160324 14:49:22 server id 2  end_log_pos 522 CRC32 0x5abe2a18  Rotate to mysql-bin.000038  pos: 4
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*/;


D:\Program Files\mysql-5.7.11-winx64\data>

看到紅色加粗部分了嗎?有木有?

在rbr模式下,sql語句引起的更改被轉換成了binlog自有的表達方式,就是藍色那段。這段代碼實際纔是有效的。纔是被複制到slave端執行的代碼。

而紅色部分是由於我們在mysqlbinlog時加了-v參數,這個參數的意思就是把藍色部分的代碼給翻譯成我們可讀的形式展示的。

下面來看看紅色部分的意思:

INSERT INTO `test`.`t1`
SET
  @1=6
  @2='azz'
  @3='bzz'
  @4='czz'
  @5='dzz'

@1,表示字段序列爲1,@1=6就是1字段將值設置爲6。以此類推。所以很明顯,如果master和slave端字段順序不一致,那麼肯定有問題。

所以mysql數據庫對字段順序是敏感的。

下面來看一個update語句對應的mysqlbinlog代碼:

執行sql是這樣的:

update t1 set c=123 where id=1;

而實際上數據庫binlog代碼是這樣的(binlog_row_image=full):

### UPDATE `test`.`t1`
### WHERE
###   @1=1
###   @2='a1'
###   @3='b2'
###   @4='c3'
###   @5='d4'
### SET
###   @1=1
###   @2='a1'
###   @3='b2'
###   @4='123'
###   @5='d4'

還是通過@4的方式表示的。delete 是:

delete from t1 where id=1;

### DELETE FROM `test`.`t1`
### WHERE
###   @1=1
###   @2='a1'
###   @3='b2'
###   @4='123'
###   @5='d4'


end。。。

而不管這個語句是否在master端引起更改。所以slave端接收到的event也是sql語句。

也就是說,在sbr裏,master端執行了什麼樣子的sql語句,那麼在slave端也要執行同樣的SQL語句。

這就會有一個現象是,同一個語句在master沒有引起更改,而在slave重演時引起了更改。或者兩端都引起了更改,但是兩端的更改不一致。

發佈了122 篇原創文章 · 獲贊 8 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章