在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)
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)
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 ~ $ mysql -u root
mysql> SET GLOBAL sql_slave_skip_counter = 1;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> slave start;
Query OK, 0 rows affected (0.00 sec)
mysql>
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。
暫時博主也還沒有發現其他特別好的方法。