MySQL使用mysqldump+binlog完整恢復被刪除的數據庫

(一)概述html

在平常MySQL數據庫運維過程當中,可能會遇到用戶誤刪除數據,常見的誤刪除數據操做有:mysql

  • 用戶執行delete,由於條件不對,刪除了不該該刪除的數據(DML操做);
  • 用戶執行update,由於條件不對,更新數據出錯(DML操做);
  • 用戶誤刪除表drop table(DDL操做);
  • 用戶誤清空表truncate(DDL操做);
  • 用戶刪除數據庫drop database,跑路(DDL操做)
  • …等

這些狀況雖然不會常常遇到,可是遇到了,咱們須要有能力將其恢復,下面講述如何恢復。sql


(二)恢復原理數據庫

若是要將數據庫恢復到故障點以前,那麼須要有數據庫全備和全備以後產生的全部二進制日誌。session

全備做用         :使用全備將數據庫恢復到上一次完整備份的位置;運維

二進制日誌做用:利用全備的備份集將數據庫恢復到上一次完整備份的位置以後,須要對上一次全備以後數據庫產生的全部動做進行重作,而重作的過程就是解析二進制日誌文件爲SQL語句,而後放到數據庫裏面再次執行。工具

舉個例子:小明在4月1日晚上8:00使用了mysqldump對數據庫進行了備份,在4月2日早上12:00的時候,小華不當心刪除了數據庫,那麼,在執行數據庫恢復的時候,須要使用4月1日晚上的完整備份將數據庫恢復到「4月1日晚上8:00」,那4月1日晚上8:00之後到4月2日早上12:00以前的數據如何恢復呢?就得經過解析二進制日誌來對這段時間執行過的SQL進行重作。測試


(三)刪庫恢復測試spa

(3.1)實驗目的3d

在本次實驗中,我直接測試刪庫,執行drop database lijiamandb,確認是否能夠恢復。


(3.2)測試過程
在測試數據庫lijiamandb中建立測試表test01和test02,而後執行mysqldump對數據庫進行全備,以後執行drop database,確認database是否能夠恢復。


STEP1:建立測試數據,爲了模擬平常繁忙的生產環境,頻繁的操做數據庫產生大量二進制日誌,我特意使用存儲過程和EVENT產生大量數據。

建立測試表:

use lijiamandb;

create table test01
 (
 id1 int not null auto_increment,
 name varchar(30),
 primary key(id1)
 );

create table test02
 (
 id2 int not null auto_increment,
 name varchar(30),
 primary key(id2)
 );


建立存儲過程,往測試表裏面插入數據,每次執行該存儲過程,往test01和test02各自插入10000條數據:

CREATE DEFINER=`root`@`%` PROCEDURE `p_insert`()
BEGIN
#Routine body goes here...
DECLARE str1 varchar(30);
DECLARE str2 varchar(30);
DECLARE i int;
set i = 0;

while i < 10000 do
 set str1 = substring(md5(rand()),1,25);
 insert into test01(name) values(str1);
 set str2 = substring(md5(rand()),1,25);
 insert into test02(name) values(str1);
 set i = i + 1;
 end while;
 END


制定事件,每隔10秒鐘,執行上面的存儲過程:

use lijiamandb;
 create event if not exists e_insert
 on schedule every 10 second
 on completion preserve
 do call p_insert();


啓動EVENT,每一個10s自動向test01和test02各自插入10000條數據

mysql> show variables like '%event_scheduler%';
+----------------------------------------------------------+-------+
| Variable_name | Value |
+----------------------------------------------------------+-------+
| event_scheduler | OFF |
+----------------------------------------------------------+-------+

mysql> set global event_scheduler = on;
 Query OK, 0 rows affected (0.08 sec)


--過3分鐘。。。
STEP2:第一步生成大量測試數據後,使用mysqldump對lijiamandb數據庫執行徹底備份
mysqldump -h192.168.10.11 -uroot -p123456 -P3306 --single-transaction --master-data=2 --events --routines --databases lijiamandb > /mysql/backup/lijiamandb.sql

注意:必需要添加--master-data=2,這樣纔會備份集裏面mysqldump備份的終點位置。

--過3分鐘。。。


STEP3:爲了便於數據庫刪除前與刪除後數據一致性校驗,先中止表的數據插入,此時test01和test02都有930000行數據,咱們後續恢復也要保證有930000行數據。

mysql> set global event_scheduler = off;
Query OK, 0 rows affected (0.00 sec)

mysql> select count(*) from test01;
 +----------+
 | count(*) |
 +----------+
 |   930000 |
 +----------+
1 row in set (0.14 sec)

mysql> select count(*) from test02;
 +----------+
 | count(*) |
 +----------+
 |   930000 |
 +----------+
1 row in set (0.13 sec)


STEP4:刪除數據庫

mysql> drop database lijiamandb;
Query OK, 2 rows affected (0.07 sec)


STEP5:使用mysqldump的全備導入

mysql> create database lijiamandb;
Query OK, 1 row affected (0.01 sec)

mysql> exit
 Bye
 [root@masterdb binlog]# mysql -uroot -p123456 lijiamandb < /mysql/backup/lijiamandb.sql 
 mysql: [Warning] Using a password on the command line interface can be insecure.


在執行全量備份恢復以後,發現只有753238筆數據:

[root@masterdb binlog]# mysql -uroot -p123456 lijiamandb 

mysql> select count(*) from test01;
 +----------+
 | count(*) |
 +----------+
 |   753238 |
 +----------+
1 row in set (0.12 sec)

mysql> select count(*) from test02;
 +----------+
 | count(*) |
 +----------+
 |   753238 |
 +----------+
1 row in set (0.11 sec)

很明顯,全量導入以後,數據不完整,接下來使用mysqlbinlog對二進制日誌執行增量恢復。


使用mysqlbinlog進行增量日誌恢復最重要的就是肯定待恢復的起始位置(start-position)和終止位置(stop-position),起始位置(start-position)是咱們執行全被以後的位置,而終止位置則是故障發生以前的位置。
STEP6:確認mysqldump備份到的最終位置

[root@masterdb backup]# cat lijiamandb.sql |grep "CHANGE MASTER"
-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000044', MASTER_LOG_POS=8526828

備份到了44號日誌的8526828位置,那麼恢復的起點能夠設置爲:44號日誌的8526828。

--接下來確認要恢復的終點位置,即執行"DROP DATABASE LIJIAMAN"以前的位置,須要到binlog裏面確認。

[root@masterdb binlog]# ls
 master-bin.000001  master-bin.000010  master-bin.000019  master-bin.000028  master-bin.000037  master-bin.000046  master-bin.000055
 master-bin.000002  master-bin.000011  master-bin.000020  master-bin.000029  master-bin.000038  master-bin.000047  master-bin.000056
 master-bin.000003  master-bin.000012  master-bin.000021  master-bin.000030  master-bin.000039  master-bin.000048  master-bin.000057
 master-bin.000004  master-bin.000013  master-bin.000022  master-bin.000031  master-bin.000040  master-bin.000049  master-bin.000058
 master-bin.000005  master-bin.000014  master-bin.000023  master-bin.000032  master-bin.000041  master-bin.000050  master-bin.000059
 master-bin.000006  master-bin.000015  master-bin.000024  master-bin.000033  master-bin.000042  master-bin.000051  master-bin.index
 master-bin.000007  master-bin.000016  master-bin.000025  master-bin.000034  master-bin.000043  master-bin.000052
 master-bin.000008  master-bin.000017  master-bin.000026  master-bin.000035  master-bin.000044  master-bin.000053
 master-bin.000009  master-bin.000018  master-bin.000027  master-bin.000036  master-bin.000045  master-bin.000054

# 屢次查找,發現drop database在54號日誌文件
[root@masterdb binlog]# mysqlbinlog -v master-bin.000056 | grep -i "drop database lijiamandb"
 [root@masterdb binlog]# mysqlbinlog -v master-bin.000055 | grep -i "drop database lijiamandb"
 [root@masterdb binlog]# mysqlbinlog -v master-bin.000055 | grep -i "drop database lijiamandb"
 [root@masterdb binlog]# mysqlbinlog -v master-bin.000054 | grep -i "drop database lijiamandb" 
drop database lijiamandb

# 保存到文本,便於搜索
[root@masterdb binlog]# mysqlbinlog -v master-bin.000054 > master-bin.txt


# 確認drop database以前的位置爲:54號文件的9019487
 # at 9019422
 #200423 16:07:46 server id 11  end_log_pos 9019487 CRC32 0x86f13148     Anonymous_GTID  last_committed=30266    sequence_number=30267   rbr_only=no
 SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
 # at 9019487
 #200423 16:07:46 server id 11  end_log_pos 9019597 CRC32 0xbd6ea5dd     Query   thread_id=100   exec_time=0     error_code=0
 SET TIMESTAMP=1587629266/*!*/;
 SET @@session.sql_auto_is_null=0/*!*/;
 /*!\C utf8 *//*!*/;
 SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
 drop database lijiamandb
 /*!*/;
 # at 9019597
 #200423 16:09:25 server id 11  end_log_pos 9019662 CRC32 0x8f7b11dc     Anonymous_GTID  last_committed=30267    sequence_number=30268   rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
 # at 9019662
 #200423 16:09:25 server id 11  end_log_pos 9019774 CRC32 0x9b42423d     Query   thread_id=100   exec_time=0     error_code=0
 SET TIMESTAMP=1587629365/*!*/;
 create database lijiamandb


STEP7:肯定了開始結束點,執行增量恢復
開始:44號日誌的8526828
結束:54號文件的9019487

這裏分爲3條命令執行,起始日誌文件涉及到參數start-position參數,單獨執行;停止文件涉及到stop-position參數,單獨執行;中間的日誌文件不涉及到特殊參數,所有一塊兒執行。

# 起始日誌文件
mysqlbinlog --start-position=8526828  /mysql/binlog/master-bin.000044 | mysql -uroot -p123456
 
# 中間日誌文件
mysqlbinlog /mysql/binlog/master-bin.000045 /mysql/binlog/master-bin.000046 /mysql/binlog/master-bin.000047 /mysql/binlog/master-bin.000048 /mysql/binlog/master-bin.000049 /mysql/binlog/master-bin.000050 /mysql/binlog/master-bin.000051 /mysql/binlog/master-bin.000052 /mysql/binlog/master-bin.000053 | mysql -uroot -p123456
 
# 終止日誌文件

mysqlbinlog --stop-position=9019487 /mysql/binlog/master-bin.000054 | mysql -uroot -p123456


STEP8:恢復結束,確認所有數據已經還原

[root@masterdb binlog]# mysql -uroot -p123456 lijiamandb
mysql> select count(*) from test01;
+----------+
| count(*) |
+----------+
|   930000 |
+----------+
1 row in set (0.15 sec)

mysql> select count(*) from test02;
+----------+
 | count(*) |
+----------+
 |   930000 |
+----------+
1 row in set (0.13 sec)


(四)總結                                                                        
1.對於DML操做,binlog記錄了全部的DML數據變化:                                                                   
     --對於insert,binlog記錄了insert的行數據                                                                   
     --對於update,binlog記錄了改變前的行數據和改變後的行數據                                                                   
     --對於delete,binlog記錄了刪除前的數據                                                                   
假如用戶不當心誤執行了DML操做,能夠使用mysqlbinlog將數據庫恢復到故障點以前。                        
                                                                                                   
   2.對於DDL操做,binlog只記錄用戶行爲,而不記錄行變化,可是並不影響咱們將數據庫恢復到故障點以前。
                                                                                                   
  總之,使用mysqldump全備加binlog日誌,能夠將數據恢復到故障前的任意時刻。 




相關文檔集合:

1.MySQL日誌--二進制日誌(binlog)                  
2.使用mysqlbinlog查看二進制日誌                  
3.MySQL使用mysqldump+binlog完整恢復被刪除的數據庫
4.使用binlog2sql工具來恢復數據庫                 
5.MySQL閃回工具—MyFlash                          

相關文章
相關標籤/搜索