1. 程式人生 > >恢復 MySQL 資料庫人為誤操作丟失的資料

恢復 MySQL 資料庫人為誤操作丟失的資料

1. 全量備份與增量備份理論基礎

1.1 全量備份

全量資料就是資料庫中的所有資料,全量備份就是把資料庫中所有的資料進行備份。

1.2 增量備份

增量資料就是從上次全量備份之後,到下一次全備之前時間段更新的新資料。對於 MySQL 來說,binlog 日誌就是 MySQL 的增量資料。

1.3 按天全備備份:每天零點做一次全備

優點:恢復時間短,維護成本低;

缺點:佔用空間多,佔用系統資源多,經常鎖表影響使用者體驗。

1.4按周全備備份:每週六零點做一次全備

優點:佔用空間小(一週一個所有資料的副本),佔用系統資源少,無需經常鎖表,使用者體驗好。

缺點:維護成本高,恢復資料麻煩,耗時長。

提示:以上優缺點都是在一般情況下,排除在從庫做備份的情況。

1.5 企業場景全量和增量備份的做法

① 中小公司,全量一般是每天一次,業務流量低估執行全備,備份時會鎖表。

② 單臺數據庫(沒有主從同步)的增量一般用 rsync 把所有的 binlog 備份到遠端伺服器;儘量做主從複製保證資料不丟失。

③ 大公司周備,每週六 0 點做一次全量備份,週日到下週六之前都是增量。

優點:節省備份時間,減小備份壓力。

缺點:增量的 binlog 檔案副本太多,還原會很麻煩。

④ 一主多從,會有一個從庫做備份,延遲同步。

1.6 MySQL 的 mysqldump 備份什麼時候能派上用場

① 遷移或者升級資料庫時;

② 增加從庫的時候;

③ 因為硬體問題或特殊異常情況,主庫或從庫宕機,主從可互相切換,這種情況下不需要備份。

④ 人為的 DDL,DML 語句誤操作,導致誤刪資料,主從庫都會執行,此時就需要備份。

⑤ 跨機房災備,需要將全量備份拷貝到異地容災環境。

1.7 什麼情況下需要增量恢復

我們在生產環境中一般常用一主多從的資料庫架構,常見的備份方案是在某一個不對外服務的從庫上開啟 binlog,然後實施定時全備和時時增量備份。

增量恢復:利用二進位制日誌和全備進行的恢復資料的過程就是增量恢復。

① 主庫或從庫宕機(硬體損壞)是否需要增量恢復?

答案:不需要增量恢復,只需要把其中一個同步最快的從庫切換為主庫即可。

② 人為操作資料庫 SQL 語句破壞主庫是否需要增量恢復?

答案:在資料庫主庫內部命令列誤操作,會導致所有的資料庫(包括主從庫)資料丟失,例如在主庫執行了 drop database test; 這樣的刪除語句,所有的從庫也會執行這個語句,從而導致所有的資料庫上的 test 庫資料丟失,這樣的場景是需要增量恢復的。

③ 只有一個主庫是否需要增量恢復?

答案:如果公司只有一個主庫的情況,首先應該做定時全量備份(一天一次)及增量備份(每隔一到十分鐘對 binlog 日誌做切割然後備份到其他伺服器上或本地其他的硬盤裡)或者寫到網路檔案系統(備份伺服器)裡。

如果不允許資料丟失,最好的辦法是做從庫,通過 drbd(基於磁碟快)的同步。

小結:一般由人為(或程式)邏輯的方式在資料庫執行的 SQL 語句等操作,才需要增量恢復,因為此時所有的從庫上也執行了誤操作語句。

1.8 MySQL 增量恢復必備條件 

① 開啟 MySQL 的記錄 binlog 日誌功能:

[[email protected] ~]# grep log-bin /etc/my.cnf

log-bin=mysql-bin

提示:主庫和備份的從庫都要開啟 binlog 記錄功能。

小結:增量恢復的條件:

存在一份全備加上全備之後的時刻到出問題時刻的所有增量 binlog 檔案備份。

② 存在 MySQL 資料庫全備:

生產環境 mysqldump 備份命令:略

在凌晨某一時刻進行資料庫全備(生產場景一般通過定時任務每日凌晨執行)。

2.  MySQL 人為誤操作丟失資料場景模擬

2.1 建立 student 表並插入資料做全備

[[email protected] ~]# mysql -uroot -p123456    

mysql> use oldboy

Database changed

mysql>  CREATE TABLE `student` (

  `id` int(4) NOT NULL AUTO_INCREMENT,

  `name` char(20) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;

INSERT INTO `student` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka'),(6,'kobe'),(7,'james'),(8,'iverson'),(9,'embid');

mysql> show tables;

| Tables_in_oldboy |

| student          |

mysql> select * from student;

| id | name    |

|  1 | oldboy  |

|  2 | oldgirl   |

|  3 | inca      |

|  4 | zuma    |

|  5 | kaka     |

|  6 | kobe     |

|  7 | james   |

|  8 | iverson |

|  9 | embid   |

[[email protected] ~]# date -s '2018/05/11'    #  修改時間為 0 點。

Fri May 11 00:00:00 CST 2018

[[email protected] ~]# mkdir /server/backup  #  建立備份的目錄。

[[email protected] ~]#  mysqldump -uroot -p123456 --master-data=2 -F -B oldboy|gzip >/server/backup/bak_$(date +%F).sql.gz   #  為 oldboy 資料庫做全備。

2.2 模擬插入資料

[[email protected] ~]# mysql -uroot -p123456   #  登陸資料庫寫資料。

mysql> use oldboy

mysql> desc student;

| Field   | Type       | Null   | Key | Default | Extra                  |

| id        | int(4)       | NO    | PRI | NULL    | auto_increment |

| name  | char(20) | NO    |         | NULL    |                           |

mysql> insert into student(name) values('oldboy101');

mysql> insert into student(name) values('oldboy102');

mysql> select * from student;    #  檢視上面插入的兩條資料。

| 10 | oldboy101 |

| 11 | oldboy102 |

2.3 模擬使用者破環資料

mysql> show databases;

| oldboy             |

mysql> drop database oldboy;  #  刪除 oldboy 庫。

mysql> show databases;  #  oldboy 庫已經不存在。    

3. 發現故障並排查原因

       資料庫出問題 10 分鐘後,公司的網站運營人員報網站故障,聯絡運維人員解決。此時,DBA 人員或開發人員通過檢視網站報錯(或者檢視後臺日誌),可以看到連不上 oldboy 庫的提示,然後通過登陸資料庫排查發現 oldboy 庫不存在了,被同事誤刪了。

提示:通過對資料庫許可權的嚴格管理及稽核可避免此類誤操作問題的發生。

4. 增量恢復過程

4.1 恢復丟失資料前提

通過防火牆禁止 web 等應用向主庫寫資料或者鎖表,讓主庫暫停時停止更新,然後再進行恢復(若允許停庫最好)。

4.2 檢查全備及 binlog 日誌

[email protected] ~]# ll /server/backup/   #  檢查全備。

-rw-r--r-- 1 root root 913 May 11 00:07 bak_2018-05-11.sql.gz

[[email protected] ~]# ll /application/mysql/data/   #  檢視 binlog 日誌。

-rw-rw---- 1 mysql mysql     1654 May 11 00:04 mysql-bin.000005

-rw-rw---- 1 mysql mysql      150 May 11 00:05 mysql-bin.000006

-rw-rw---- 1 mysql mysql      150 May 11 00:07 mysql-bin.000007

-rw-rw---- 1 mysql mysql      662 May 11 00:19 mysql-bin.000008

-rw-rw---- 1 mysql mysql      152 May 11 00:07 mysql-bin.index

[[email protected] ~]# cd /server/backup/

[[email protected] backup]# ll

-rw-r--r-- 1 root root 913 May 11 00:07 bak_2018-05-11.sql.gz

[[email protected] backup]# gzip -d bak_2018-05-11.sql.gz

[[email protected] backup]# grep -i "change" bak_2018-05-11.sql

-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000008', MASTER_LOG_POS=107;  

4.3 立即重新整理並備份出增量 binlog 資料

[[email protected] backup]# mysqladmin -uroot -p123456 flush-logs   #  重新整理 binlog 。

[[email protected] backup]# ll /application/mysql/data/   #  檢視。

-rw-rw---- 1 mysql mysql      705 May 11 00:42 mysql-bin.000008   #  需要恢復的 binlog(誤操作語句)。

-rw-rw---- 1 mysql mysql      107 May 11 00:42 mysql-bin.000009   #  插入新資料的 binlog(人為誤操作後用戶插入其他資料)。

[[email protected] backup]# cp /application/mysql/data/mysql-bin.000008 /server/backup/  #  備份增量(全備以後的含有誤操作語句的增量)。

[[email protected] backup]# ll /server/backup/

-rw-r--r-- 1 root root 2284 May 11 00:07 bak_2018-05-11.sql

-rw-r----- 1 root root  705 May 11 00:46 mysql-bin.000008

[[email protected] backup]# mysqlbinlog -d oldboy mysql-bin.000008

[[email protected] backup]# mysqlbinlog -d oldboy mysql-bin.000008 >bin.sql

[[email protected] backup]# vi bin.sql   #  找到 drop database oldboy; 誤操作語句並把它刪掉。

[[email protected] backup]# ll   #  把下面的兩個恢復進去即可。

-rw-r--r-- 1 root root 2284 May 11 00:07 bak_2018-05-11.sql   #  全量。

-rw-r--r-- 1 root root 2352 May 11 00:50 bin.sql                        #  清除誤操作語句的增量資料。

4.4 問題:恢復資料的語句會記錄到新的 binlog 檔案中

mysql> show variables like '%log_bin%';

| Variable_name                                    | Value |

| log_bin                                                | ON    |

| log_bin_trust_function_creators          | OFF   |

| sql_log_bin                                         | ON    |    

#  該引數改為 off 就可以不記錄恢復過程,但是使用者寫入資料也無法記錄了。因為此處沒有使用者往資料庫寫入資料,企業場景會通過防火牆不讓使用者寫入或者讓使用者只讀。

4.5 開始恢復資料

[[email protected] backup]# mysql -uroot -p123456 <bak_2018-05-11.sql  # 恢復全量備份。

[[email protected] backup]# mysql -uroot -p123456 oldboy <bin.sql                       # 恢復增量備份。

[[email protected] backup]#  mysql -uroot -p123456     #  檢視資料恢復結果。

mysql> show databases;

| oldboy             |

mysql> use oldboy

mysql> select * from student;

|  1 | oldboy        |

|  2 | oldgirl         |

|  3 | inca            |

|  4 | zuma          |

|  5 | kaka           |

|  6 | kobe           |

|  7 | james         |

|  8 | iverson       |

|  9 | embid         |

| 10 | oldboy101 |

| 11 | oldboy102  |

5. 案例總結

5.1 增量恢復小結

① 人為 SQL 造成的誤操作;

② 全備和增量;

③ 恢復時建議對外停止更新;

④ 恢復全量,然後把增量日誌中有問題的 SQL 語句刪除,恢復到資料庫。

5.2 增量恢復核心思想

① 流程制度控制,防止問題發生。如果不做流程制度控制,就會面臨停止服務和丟失資料之間的取捨;

② 在業務上對一些資訊做監控,黑名單,白名單機制。(通過流程制度控制不加 while 語句不能執行等);

③ 根據業務需求容忍度,制定一個可量化的目標,根據需求來選擇停庫或鎖表或者容忍丟失部分資料。