主從遇到的各種問題的詳細解決方法

主從同步維護

由於特殊情況,主服務器更新頻繁,從服務器由於各種原因,導致更新特別慢,這種情況,我們需要定期進行主從的數據同步維護,具體方法如下,在負載較低的時候暫時阻塞主數據庫更新,強制主從數據庫的更新同步

操作1、在master上執行以下語句:

mysql> FLUSH TABLES WITH READ LOCK; 
Query OK, 0 rows affected (0.01 sec) 
 mysql> SHOW MASTER STATUS; 
+------------------+----------+--------------+------------------+ 
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | 
+------------------+----------+--------------+------------------+ 
| mysql-bin.000039 | 974      |              |                  | 
+------------------+----------+--------------+------------------+ 
1 row in set (0.00 sec) 
記錄 SHOW語句的輸出的日誌名和偏移量,這些是從服務器複製的目的座標。

2、在從服務器上,執行下面語句,其中 MASTER_POS_WAIT()函數的參數是前面步驟中得到的複製座標值:

mysql> select MASTER_POS_WAIT('mysql-bin.000039','974'); 
+-------------------------------------------+ 
| MASTER_POS_WAIT('mysql-bin.000039','974') | 
+-------------------------------------------+ 
| 0                                         | 
+-------------------------------------------+ 
1 row in set (0.00 sec) 
這個 SELECT語句會阻塞直到從服務器達到指定的日誌文件和偏移量後,返回0,如果返回-1,則表示超時退出。查詢返回0 時,則從服務器與主服務器同步。

3、在主服務器上,執行下面的語句允許主服務器重新開始處理更新:

mysql> UNLOCK TABLES; 
Query OK, 0 rows affected (0.00 sec) 

從服務器複製出錯的處理

在某些情況下、會遇到從服務器複製出錯的情況,首先,
1、確定是否是從服務器的表與主服務器的不同造成的。如果是表結構不同導致的,則修改從服務器的表與主服務器的相同,然後重新運行START SLAVE 語句。 
2、如果不是表結構不同導致的更新失敗,則需要確認手動更新是否安全,然後忽視來自主服務器的更新失敗的語句。跳過來自主服務器的語句的命令爲SET GLOBAL 

SQL_SLAVE_SKIP_COUNTER = n,其中 n 的取值爲 1 或者 2。如果來自主服務器的更新語句不使用 AUTO_INCREMENT或 LAST_INSERT_ID(),n 值應爲 1,否則,值應爲 2。原因是使用 AUTO_INCREMENT或 LAST_INSERT_ID()的語句需要從二進制日誌中取兩個事件。以下例子就是在從服務器端模擬跳過主服務器的兩個更新語句的效果。 

1、   首先,在從服務器端先停止複製進程,並設置跳過兩個語句:

mysql> select * from repl_test; 
+------+ 
| id   | 
+------+ 
| 1    | 
+------+ 
1	row in set (0.00 sec) 
 
mysql> stop slave; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> SET GLOBAL SQL_slave_SKIP_COUNTER = 2; Query OK, 0 rows affected (0.01 sec) 
2、 然後在主服務器端插入 3條記錄:

mysql> select * from repl_test; 
+------+ 
| id   | 
+------+ 
| 1    | 
+------+ 
1	row in set (0.00 sec) 
 
mysql> insert into repl_test values(2); Query OK, 1 row affected (0.00 sec) 
 
mysql> insert into repl_test values(3); Query OK, 1 row affected (0.00 sec) 
 
mysql> insert into repl_test values(4); Query OK, 1 row affected (0.00 sec) 
 mysql> select * from repl_test; 
+------+ 
| id   | 
+------+ 
| 1    | 
| 2    | 
| 3    | 
| 4    | 
+------+ 
4 rows in set (0.00 sec) 
3、從服務器端啓動複製進程,檢查測試的表,發現首先插入的兩條記錄被跳過了,只執行了第3 條插入語句:
mysql> start slave; 
Query OK, 0 rows affected (0.00 sec) 
 mysql> select * from repl_test; 
+------+ 
| id   | 
+------+ 
| 1    | 
| 4    | 
+------+ 
2 rows in set (0.00 sec) 

多主複製時的自增長變量衝突問題

某些情況下,可能會需要使用多主複製(多臺主服務器對一臺從服務器)。這個時候,如果主服務器的表採用自動增長變量,那麼複製到從服務器的同一張表後很可能會引起主鍵衝突,因爲系統參數auto_increment_incrementauto_increment_offset默認值爲1,這樣多臺主服務器的自增變量列遲早會發生衝突。

在單主複製時,可以採用默認設置,不會有主鍵衝突發生。但是使用多主複製時,就需要定製auto_increment_increment 和 auto_increment_offset 的設置,保證多主之間複製到從數據庫不會有重複衝突。比如,兩個 master的情況可以按照以下設置。

Master1上:auto_increment_increment= 2,auto_increment_offset= 1;(1,3,5,7…序列)。

Master2上:auto_increment_increment= 2,auto_increment_offset= 0;(0,2,4,6…序列)。

下面的例子中創建了測試表ai,只有一個自增字段 i,我們開始演示修改這兩個參數的效果。

首先在參數是默認值的時候,往表 ai 中插入記錄,可以看到自動增長列的值是連續的。

mysql> CREATE TABLE ai ( 
    ->   i bigint(20) NOT NULL AUTO_INCREMENT, 
    ->   PRIMARY KEY (i) 
    -> ) ENGINE=MyISAM DEFAULT CHARSET=gbk; 
Query OK, 0 rows affected (0.03 sec) 
 mysql> SHOW VARIABLES LIKE 'auto_inc%'; +--------------------------+-------+ 
| Variable_name            | Value | 
+--------------------------+-------+ 
| auto_increment_increment | 1     | 
| auto_increment_offset    | 1     | 
+--------------------------+-------+ 
2 rows in set (0.00 sec) 
 
mysql> insert into ai values(null),(null),(null); 
Query OK, 3 rows affected (0.00 sec) 
Records: 3  Duplicates: 0  Warnings: 0 
 mysql> select * from ai; 
+---+ 
| i | 
+---+ 
| 1 | 
| 2 | 
| 3 | 

然後把參數 auto_increment_increment 的值修改成 10,再插入記錄:

mysql> SET @@auto_increment_increment=10; 
Query OK, 0 rows affected (0.00 sec) 
 mysql> SHOW VARIABLES LIKE 'auto_inc%'; +--------------------------+-------+ 
| Variable_name            | Value | 
+--------------------------+-------+ 
| auto_increment_increment | 10    | 
| auto_increment_offset    | 1     | 
+--------------------------+-------+ 
2 rows in set (0.00 sec) 
 
mysql> insert into ai values(null),(null),(null); 
Query OK, 3 rows affected (0.00 sec) 
Records: 3  Duplicates: 0  Warnings: 0 
 mysql> select * from ai; 
+----+ | i  | +----+ | 1  | 
| 2  | 
| 3  | 
| 11 | 
| 21 | 
| 31 | +----+ 
6 rows in set (0.00 sec) 

從測試的結果上看,新插入的記錄不再連續了,每次增加 10 。接着再修改 auto_increment_offset 參數,瞭解插入記錄的效果:

mysql> SET @@auto_increment_offset=5; 
Query OK, 0 rows affected (0.00 sec) 
 mysql> SHOW VARIABLES LIKE 'auto_inc%'; +--------------------------+-------+ 
| Variable_name            | Value | 
+--------------------------+-------+ 
| auto_increment_increment | 10    | 
| auto_increment_offset    | 5     | 
+--------------------------+-------+ 
2 rows in set (0.00 sec) 
 
mysql> insert into ai values(null),(null),(null); 
Query OK, 3 rows affected (0.00 sec) 
Records: 3  Duplicates: 0  Warnings: 0 
 mysql> select * from ai; 
+----+ | i  | +----+ | 1  | 
| 2  | 
| 3  | 
| 11 | 
| 21 | 
| 31 | 
| 35 | 
| 45 | 
| 55 | +----+ 
9 rows in set (0.00 sec) 

從插入記錄的結果上可以瞭解,auto_increment_offset參數設置的是每次增加後的偏移量,也就是每次按照10 累加之後,還需要增加 5 個偏移量。

通過這兩個參數可以方便地設置不同的主服務器上的自動增長列的值的範圍,這樣在這些數據複製到從服務器上時可以有效地避免主鍵的重複。


切換主從服務器

一個主數據庫服務器 M,兩個從數據庫服務器 S1、S2 同時指向主數據庫服務器 M。當主數據庫 M 因爲某種原因出現故障的時候,需要將其中的一個從數據庫服務器(假設選中S1)切換成主數據庫服務器,同時修改另一個從數據庫(S2)的配置,使其指向新的主數據庫(S1)。此外還需要通知應用修改主數據庫的 IP地址,如果可能,將出現故障的主數據庫(M)修復或者重置成新的從數據庫。

下面詳細介紹一下切換主從服務器的操作步驟。

1、首先要確保所有的從數據庫都已經執行了 relay log 中的全部更新,在每個從服務器上,執行 STOP SLAVEIO_THREAD,然後檢查 SHOWPROCESSLIST 的輸出,直到看到狀態是 Hasread all relay log,表示更新都執行完畢。
mysql> STOP SLAVE IO_THREAD; 
Query OK, 0 rows affected (0.00 sec) 
 mysql> SHOW PROCESSLIST \G 
*************************** 1. row *************************** 
     Id: 2 
   User: system user    Host:  
     db: NULL 
Command: Connect 
   Time: 4137 
  State: Has read all relay log; waiting for the slave I/O thread to update it    Info: NULL 
*************************** 2. row *************************** 
…… 
2 rows in set (0.00 sec) 
2、在從數據庫 S1 上,執行 STOP SLAVE 停止從服務,然後 RESETMASTER 重置成主數據庫。
mysql> STOP SLAVE; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> reset master; 
Query OK, 0 rows affected (0.06 sec) 
3、S2 上,執行 STOPSLAVE 停止從服務,然後執行CHANGE MASTER TO MASTER_HOST = 'S1'重新設置主數據庫,然後再執行START SLAVE 啓動複製。

mysql> STOP SLAVE; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> CHANGE MASTER TO MASTER_HOST = '192.168.1.101'; 
Query OK, 0 rows affected (0.05 sec) 
 
mysql> start slave; 
Query OK, 0 rows affected (0.00 sec) 
4、通知所有的客戶端將應用指向 S1,這樣客戶端發送的所有的更新語法寫入到 S1 的二進制日誌。
5、刪除新的主數據庫服務器上的master.inforelay-log.info文件,否則下次重啓的時候還會按照從服務器啓動。

6、最後,如果M服務器可以修復,則可以按照S2的方法配置成S1 的從服務器。

注意:上面測試的步驟是默認 S1 是打開 log-bin 選項的,這樣重置成主數據庫後可以將二進制日誌傳輸到其他從服務器。其次,S1上沒有打開 log-slave-updates參數,否則重置成主數據庫後,可能會將已經執行過的二進制日誌重複傳輸給S2,導致S2 的同步錯誤。




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