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