Mysql集羣的HA原理及配置指南之字段衝突修復(四)

在master-master的構架中,一臺mysql機器可能會down掉,但是數據依然是在往另一臺寫的,但是當down掉的mysql起起來了我們會發現很多問題,其中最明顯的就是由於AUTO_INCREMENT的主鍵導致的數據同步ERROR問題,話不多說,直接乾貨上:


Start:

1.首先準備2臺master-master雙主構架的機器,之前的文章(二)有講這個模式的配置方式,先測試2臺機器的同步:

數據庫a插入信息:

a ~ $ mysql -u root
mysql> INSERT INTO important.stuff SET details='Gift from A to B';
Query OK, 1 row affected (0.03 sec)

數據庫b同步:

b ~ $ mysql -u root
mysql> SELECT * FROM important.stuff ORDER BY id DESC LIMIT 1\G
*************************** 1. row ***************************
      id: 7
 details: Gift from A to B
happened: 2013-03-27 04:09:40
1 rows in set (0.00 sec)

反過來數據庫b插入數據:

mysql> INSERT INTO important.stuff SET details='Gift from B to A';
Query OK, 1 row affected (0.03 sec)

mysql>

數據庫a同步:

mysql> INSERT INTO important.stuff SET details='Gift from B to A';
Query OK, 1 row affected (0.03 sec)

mysql>

2.在a,b上停止I/O thread,即停止數據備份同步:

mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.01 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State:
                  Master_Host: a.example.com
                  Master_User: replicator
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 3415
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 803
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: No
            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: 3415
              Relay_Log_Space: 959
              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: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 20
1 row in set (0.00 sec)

mysql>

3.在a中插入數據:

mysql> INSERT INTO important.stuff SET details='Unique data from A';
Query OK, 1 row affected (0.03 sec)

在b中也插入數據:

mysql> INSERT INTO important.stuff SET details='Unique data from B';
Query OK, 1 row affected (0.03 sec)


4.在a,b上開啓slave:

mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

5.檢查slave狀態,我們會發現會有key的錯誤:

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: b.example.com
                  Master_User: replicator
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 4127
               Relay_Log_File: mysql-relay-bin.000003
                Relay_Log_Pos: 253
        Relay_Master_Log_File: mysql-bin.000001
             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: 1062
                   Last_Error: Error 'Duplicate entry '11' for key 'PRIMARY'' on query. Default database: ''. Query: 'INSERT INTO important.stuff SET details='Unique data from B''
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 3884
              Relay_Log_Space: 1585
              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: 0
                Last_IO_Error:
               Last_SQL_Errno: 1062
               Last_SQL_Error: Error 'Duplicate entry '11' for key 'PRIMARY'' on query. Default database: ''. Query: 'INSERT INTO important.stuff SET details='Unique data from B''
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 20
1 row in set (0.00 sec)

mysql>


到這一步大家應該都知道文章開頭說的ERROR原因了,由於auto_increment的key導致兩張表裏面在slave關閉是插入的數據的id是一樣的,但是數據內容不一樣這就導致了數據庫報錯。

6.爲解決這個Replication ERROR,我們需要在A中修改配置文件:

mysql> exit
a ~ $ sudoedit /etc/my.cnf


[mysqld]
auto_increment_increment = 2
auto_increment_offset = 1
relay_log = mysql-relay-bin
log_slave_updates = 1
log_bin = mysql-bin
server_id = 10

重啓mysql:

a ~ $ sudo service mysqld restart
Stopping mysqld:                                           [  OK  ]
Starting mysqld:                                           [  OK  ]


在b中同樣修改配置文件:

mysql> exit
b ~ $ sudoedit /etc/my.cnf

[mysqld]
auto_increment_increment = 2
auto_increment_offset = 2
relay_log = mysql-relay-bin
log_slave_updates = 1
log_bin = mysql-bin
server_id = 20

重啓Mysql服務:

b ~ $ sudo service mysqld restart
Stopping mysqld:                                           [  OK  ]
Starting mysqld:                                           [  OK  ]

7.在b中查看ERROR:

b ~ $ mysql -u root
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: a.example.com
......some content not shown
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 1062
                   Last_Error: Error 'Duplicate entry '11' for key 'PRIMARY'' on query. Default database: ''. Query: 'INSERT INTO important.stuff SET details='Unique data from B''
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 3882

在表中查找這條id = 11的數據:

mysql> select * from important.stuff where id=11;
+----+--------------------+---------------------+
| id | details            | happened            |
+----+--------------------+---------------------+
| 11 | Unique data from B | 2013-04-06 19:33:44 |
+----+--------------------+---------------------+
1 row in set (0.00 sec)

mysql>


關閉b數據庫中的sql_log_bin參數(具體作用見前面文章),並檢查是否關閉,且刪除那條衝突的數據

mysql> SET sql_log_bin="OFF";
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like "sql_log_bin";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_bin   | OFF   |
+---------------+-------+
1 row in set (0.00 sec)

mysql> delete from important.stuff where id=11;

將sql_log_bin打開並插入和之前相同的數據
mysql> SET sql_log_bin="ON";
Query OK, 0 rows affected (0.00 sec)
mysql> insert into important.stuff VALUES(NULL, 'Unique data from B', '2013-04-06 19:33:44');
Query OK, 1 row affected (0.02 sec)


會發現這次插入的數據id = 12
mysql> select * from important.stuff order by id DESC LIMIT 1;
+----+--------------------+---------------------+
| id | details            | happened            |
+----+--------------------+---------------------+
| 12 | Unique data from B | 2013-04-06 19:33:44 |
+----+--------------------+---------------------+
1 row in set (0.00 sec)

mysql>

啓動b的slave

mysql> slave start;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: a.example.com
                  Master_User: replicator
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 107
               Relay_Log_File: mysql-relay-bin.000006
                Relay_Log_Pos: 253
        Relay_Master_Log_File: mysql-bin.000002
             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: 107
              Relay_Log_Space: 555
              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: 10
1 row in set (0.00 sec)

會發現a的數據同步進來了,b已恢復正常
mysql> select * from important.stuff where id >= 11;
+----+--------------------+---------------------+
| id | details            | happened            |
+----+--------------------+---------------------+
| 11 | Unique data from A | 2013-04-06 19:33:44 |
| 12 | Unique data from B | 2013-04-06 19:33:44 |
+----+--------------------+---------------------+
2 rows in set (0.00 sec)

mysql>


在a數據庫中,我們需要避免b中的之前的衝突數據插入進來
a ~ $ mysql -u root
mysql> SET GLOBAL sql_slave_skip_counter = 1;
Query OK, 0 rows affected (0.00 sec)

mysql>


啓動a的slave
mysql> slave start;
Query OK, 0 rows affected (0.00 sec)

mysql>


會發現a表存進了b中id=12的數據,此時a也恢復正常
mysql> select * from important.stuff where id >= 11;
+----+--------------------+---------------------+
| id | details            | happened            |
+----+--------------------+---------------------+
| 11 | Unique data from A | 2013-04-06 19:33:44 |
| 12 | Unique data from B | 2013-04-06 19:33:44 |
+----+--------------------+---------------------+
2 rows in set (0.00 sec)

mysql>


總結:

      由於自動增加的主鍵在雙主模式數據庫down掉時發生的數據conflict問題,我們可以通過修改/etc/my.cnf配置文件修改auto increment的步長從而解決ERROR。

暫時博主也還沒有發現其他特別好的方法。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章