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

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

主庫插入資料:

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執行緒還是實時在工作的。

3.MySQL延遲複製原理解析

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

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

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

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

4.MySQL延遲複製恢復案例實踐

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

(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)

(2)模擬在主庫寫入資料

每隔5秒寫入1個庫,就當模擬使用者寫入資料了。

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

> do

>     mysql -e “create database oldboy$n”

>     sleep 5

> done

提示:Shell指令碼知識可參考《跟老男孩學習Linux運維:Shell程式設計實戰》一書。

(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)

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

(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。

(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日誌到從庫了。

(6)從庫暫停主從複製,並檢查資料

從庫上執行stop slave;暫停主從複製,並檢視資料庫是否同步過來。

mysql> stop slave;

mysql> show databases;

+——————–+

| Database           |

+——————–+

| information_schema |

| alex_python        |

| mysql              |

| performance_schema |

+——————–+

4 rows in set (0.00 sec)

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

(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

(8)解析需要的中繼日誌

解析SQL執行緒未解析的全部剩餘relay-bin中繼日誌資料,由於模擬資料量不夠大,因此本例裡只有db02-relay-bin.000002一箇中繼日誌,實際工作中可能有多個,一併解析到一個指定檔案或者分不同的檔案存放也可。

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

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

(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   

#檢查刪除結果。

(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指向該“延遲從庫”,即新主庫提供使用者訪問,然後,在對其他的破壞的主從資料庫進行修復。