1. 程式人生 > >MySQL主從延遲復制實踐及生產故障案例恢復實踐

MySQL主從延遲復制實踐及生產故障案例恢復實踐

-s running wait 命令 情況 是把 找到 時間段 註意

1.1

MySQL主從延遲復制介紹

從MySQL5.6開始支持了主從延遲復制,這個功能主要解決的問題是,當主庫有邏輯的數據刪除或錯誤更新後,所有的從庫都會進行錯誤的更新,從而導致所有的數據庫數據異常,即使有定時的備份數據可以用於數據恢復,特別是數據庫數據量很大時,恢復時間會很長,再恢復期間數據庫數據被刪或錯誤數據影響正常的訪問體驗。

而延遲復制就可以較好的解決這個問題。例如,可以設定某一個從庫和主庫的更新延遲1小時,這樣主庫數據出問題以後,1個小時以內發現,可以對這個從庫進行無害恢復處理,使之依然是正確的完整的數據,省去了數據恢復占用的時間,用戶體驗有所增加。

1.2

MySQL主從延遲復制配置實踐

MySQL5.6版本的延遲復制配置,是通過在Slave上執行以下命令實現的:

CHANGE MASTER TO MASTER_DELAY = N;
#讀者可在配置延遲從庫Change Master時直接加上MASTER_DELAY選項。

該語句設置Slave數據庫延時N秒後,再與主數據庫進行數據復制,具體操作為登錄到Slave數據庫服務器(本文是52) ,然後執行如下命令。

mysql> stop slave;

Query OK, 0 rows affected (0.45 sec)

mysql> CHANGE MASTER TO MASTER_DELAY = 20;

#這是延遲的核心命令。

Query OK, 0 rows affected (0.22 sec)

mysql> start slave;

Query OK, 0 rows affected (0.15 sec)

mysql> show slave status\G

*************************** 1. row ***************************

...省略若幹...

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

...省略若幹...

SQL_Delay: 20

#這裏的數字就是設置的延遲20秒後進行復制。

SQL_Remaining_Delay: NULL

#還剩多少秒執行復制。

Slave_SQL_Running_State: Slavexx to update it

#SQL線程的狀態。

...省略若幹...

1 row in set (0.09 sec)

復制狀態裏常用的三個狀態參數為SQL_Delay、SQL_Remaining_Delay、Slave_SQL_Running_State,說明上面已分別註釋了。

主庫插入數據:

mysql> create database lanlan;

Query OK, 1 row affected (0.00 sec)

主庫插入完數據1秒以後,從庫執行show databases;查看數據是否及時同步了,結果如下:

mysql> show databases;

+--------------------+

| Database |

+--------------------+

| information_schema |

| alex_python |

| mysql |

| performance_schema |

+--------------------+

在從庫上並沒有看到在主庫上創建的數據庫lanlan,此時執行間歇性的執行show slave status\G查看延遲的參數狀態如下輸出。

mysql> show slave status\G

...省略若幹...

SQL_Delay: 20

SQL_Remaining_Delay: 13

#剩於13秒執行復制。

Slave_SQL_Running_State: Waiting until MASTER_DELAY seconds after master executed event

...省略若幹...

1 row in set (0.00 sec)

mysql> show slave status\G

...省略若幹...

SQL_Delay: 20

SQL_Remaining_Delay: 9

#剩於9秒執行復制。

Slave_SQL_Running_State: Waiting until MASTER_DELAY seconds after master executed event

...省略若幹...

1 row in set (0.00 sec)

mysql> show slave status\G

...省略若幹...

SQL_Delay: 20

SQL_Remaining_Delay: NULL

#復制完成後,沒有新數據更新的狀態。

Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it

...省略若幹...

1 row in set (0.00 sec)

在從庫沒有更新數據處於延遲復制沒到時間期間,查看從庫的中繼日誌。

[[email protected] data]# pwd

/application/mysql/data

[[email protected] data]# mysqlbinlog db02-relay-bin.000002

SET @@session.lc_time_names=0/*!*/;

SET @@session.collation_database=DEFAULT/*!*/;

create database lanlan

#中繼日誌確已經有了創建的語句,說明IO線程還是實時在工作的。

1.3

MySQL延遲復制原理解析

MySQL的延遲復制實際上影響的只是SQL線程將數據應用到從數據庫,而I/O線程早已經把主庫更新的數據寫入到了從庫的中繼日誌中,因此,在延遲復制期間即使主庫宕機了,從庫到了延遲復制的時間,依然會把數據更新到和主庫宕機時一致。

特別提示:其實MySQL的延遲復制的功能早在幾年前,老男孩老師就已經用思想實現了這個功能, 並應用於企業生產備份和恢復中了,方法如下:

1)15.2節已經介紹過的,執行mysql> stop slave sql_thread;把SQL線程停掉,然後進行備份,備份期間主庫宕機,但是主庫的Binlog依然會及時發到從庫,最終從庫依然可以恢復到和主庫宕機前的狀態。

2)寫一個腳本,利用定時任務控制sql_thread的停止和運行,進而庫就可以控制實現簡單的從庫延遲復制功能了,這就是思想的重要性。當然了5.6版本就用軟件提供的功能吧,5.6以前的數據庫要想實現延遲復制,可以思考下老男孩曾經用過的延遲備份以及延遲復制的思路。

1.4 MySQL延遲復制恢復案例實踐

在企業中,我們要根據業務需求給延遲復制指定一個時間段,例如1個小時後進行該從庫復制,那麽在這一個小時內,如果主庫誤更新了數據,那麽其他的從庫也都傻傻地誤更新了數據,如何將這個延遲的從庫恢復正常沒有誤更新數據前的完整狀態呢?且看下文的實踐。

1.4.1 將從庫延遲調整為1小時

模擬環境,將從庫延遲調整為3600秒;

mysql> stop slave;

Query OK, 0 rows affected (0.00 sec)

mysql> CHANGE MASTER TO MASTER_DELAY = 3600;

Query OK, 0 rows affected (0.03 sec)

mysql> start slave;

Query OK, 0 rows affected (0.08 sec)

mysql> show slave status\G

...省略若幹...

SQL_Delay: 3600

SQL_Remaining_Delay: 2414

Slave_SQL_Running_State: Waiting until MASTER_DELAY seconds after master executed event

...省略若幹...

1 row in set (0.00 sec)

1.4.2 模擬在主庫寫入數據

每隔5秒寫入1個庫,就當模擬用戶寫入數據了。

[[email protected] ~]# for n in {1..5}

> do

> mysql -e "create database oldboy$n"

> sleep 5

> done

提示:Shell腳本知識可參考《跟老男孩學習Linux運維:Shell編程實戰》一書。

1.4.3 模擬人為破壞數據

模擬人為破壞數據也可以是不帶where的update語句。

mysql> drop database oldboy5;

#刪除oldboy5數據庫,後面就是把這個數據恢復回來,別的數據還得有。

Query OK, 0 rows affected (0.00 sec)

mysql> show databases like ‘oldboy%‘;

+--------------------+

| Database (oldboy%) |

+--------------------+

| oldboy1 |

| oldboy2 |

| oldboy3 |

| oldboy4 |

+--------------------+

4 rows in set (0.00 sec)

#此時,所有的從庫都已經是壞數據了,只有延遲從庫是好的,但是是一小時前的數據。

1.4.4 停止寫庫恢復數據

當數據庫出現誤刪數據情況時,要想完整恢復數據(特別是update不加條件破壞數據),最好選擇對外停止訪問措施,需要犧牲用戶體驗,除非業務可以忍受數據不一致,並且不被二次破壞。從庫可以適當繼續開放給用戶讀訪問,但是也可能會導致用戶讀到的數據是壞的數據,需要讀者去衡量數據一致性和用戶體驗的問題。本例使用iptables封堵用戶對主庫的所有訪問。

[[email protected] ~]# iptables -I INPUT -p tcp --dport 3306 ! -s 172.16.1.51 -j DROP

#非172.16.1.51禁止訪問數據庫3306端口,51是主庫IP。

1.4.5 檢查Binlog發送和接收是否完成

登錄主庫執行show processlist;對Binlog是否全部發送到該延遲從庫進行確認,當然了,也可以登錄延遲從庫執行show processlist;對從庫IO線程是否接收完全部Binlog進行狀態查詢確認。

mysql> show processlist;

+----+---------------------------------------+---------------+

| 12 | rep | 172.16.1.52:39043 | NULL | Binlog Dump | 709 | Master has sent all binlog to slave; waiting for binlog to be updated | NULL |

+----+------------------------------------+------------------+

2 rows in set (0.00 sec)

#上述提示表示主庫已經發送完所有Binlog日誌到從庫了。

1.4.6 從庫暫停主從復制,並檢查數據

從庫上執行stop slave;暫停主從復制,並查看數據庫是否同步過來。

mysql> stop slave;

mysql> show databases;

+--------------------+

| Database |

+--------------------+

| information_schema |

| alex_python |

| mysql |

| performance_schema |

+--------------------+

4 rows in set (0.00 sec)

#提示:因為延遲時間還未到,因此數據不會同步到該延遲從庫。

1.4.7

定位恢復數據對應中繼日誌

根據relay-log.info記錄的SQL線程讀取relay-log的的位置解析未應用到從庫的relay-bin日誌。

[[email protected] data]# pwd

#進入到中繼日誌所在的目錄。

/application/mysql/data

[[email protected] data]# ls -l *relay*

#查看中繼日誌相關信息。

-rw-rw----. 1 mysql mysql 172 9月 13 17:32 db02-relay-bin.000001

-rw-rw----. 1 mysql mysql 993 9月 13 17:37 db02-relay-bin.000002

-rw-rw----. 1 mysql mysql 48 9月 13 17:32 db02-relay-bin.index

-rw-rw----. 1 mysql mysql 61 9月 13 17:32 relay-log.info

#SQL線程讀取中繼日誌位置信息。

[[email protected] data]# cat relay-log.info

#查看中繼日誌應用的位置信息。

7

./db02-relay-bin.000002 #SQL線程讀取中繼日誌的文件名信息。

284 #SQL線程讀取中繼日誌位置點信息。

oldboy-bin.000024

309

3600

0

1

1.4.8

解析需要的中繼日誌

解析SQL線程未解析的全部剩余relay-bin中繼日誌數據,由於模擬數據量不夠大,因此本例裏只有db02-relay-bin.000002一個中繼日誌,實際工作中可能有多個,一並解析到一個指定文件或者分不同的文件存放也可。

[[email protected] data]# mysqlbinlog --start-position=284 db02-relay-bin.000002 >relay.sql

#根據上述的relay-log.info的中級日誌文件和位置信息進行解析中繼日誌,此命令的用法前面章節已經講解過了,此不累述。

1.4.9

從解析文件中刪除問題SQL

將破壞數據庫數據的SQL語句找到並從已解析的SQL語句中刪除,這裏就是“drop database oldboy5”。

[[email protected] data]# egrep "drop database oldboy5" relay.sql

#檢查是否存在誤刪的SQL語句。

drop database oldboy5

[[email protected] data]# sed -i ‘/drop database oldboy5/d‘ relay.sql

#刪除,註意別刪多了。

[[email protected] data]# egrep "^drop database oldboy5" relay.sql

#檢查刪除結果。

1.4.10

將處理好的SQL文件恢復到數據庫

將解析後並處理好的relay.sql數據文件恢復到延遲從庫。

[[email protected] data]# mysql<relay.sql

#這步就是從停止slave復制開始,根據relay-log.info位置手工將剩下的所有日誌數據恢復到數據庫中,需要註意就是提前要清理破壞數據庫的語句,在恢復。

[[email protected] data]# mysql -e "show databases like ‘oldboy%‘;"

+--------------------+

| Database (oldboy%) |

+--------------------+

| oldboy1 |

| oldboy2 |

| oldboy3 |

| oldboy4 |

| oldboy5 | #被刪除的oldboy5數據庫已經找回。

+--------------------+

到此,利用延遲數據庫恢復數據完畢,將此庫提升為主庫(見手工實現主從角色切換章節內容),將VIP指向該“延遲從庫”,即新主庫提供用戶訪問,然後,在對其他的破壞的主從數據庫進行修復。

MySQL主從延遲復制實踐及生產故障案例恢復實踐