?hello,大家好,我是張張,「架構精進之路」公號作者。
在我們實際工作中,尤其在公司的測試環境下,經常會有多個業務方服務共用同一套服務器,部署自身MySQL環境。很不巧的是,會出現有MySQL數據文件被刪除/誤刪除的情況發生。假如真的發生了,想想就很令人崩潰對不對?
先別著急,今天來跟大家分享一個對于MySQL數據文件被誤刪除后嘗試恢復的辦法。一旦發生上述情況,同時實例數據未做備份,是否有機會進行數據恢復呢?
接下來,就讓我們來嘗試下數據恢復過程的演示:
1.構建模擬數據
模擬數據準備:
CREATE TABLE `t1` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
mysql> select * from t1;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+------+
5 rows in set (0.00 sec)
2.刪除數據文件
在操作系統層進行數據文件的刪除。
[root@admin-db12 test]# ll
total 112
-rw-r----- 1 mysql mysql 67 Nov 22 10:01 db.opt
-rw-r----- 1 mysql mysql 8556 Nov 22 11:48 t1.frm
-rw-r----- 1 mysql mysql 98304 Nov 22 11:48 t1.ibd
[root@admin-db12 test]# pwd
/mysql/dba/mysql/multi/3303/data/test
[root@admin-db12 test]# ll
total 112
-rw-r----- 1 mysql mysql 67 Nov 22 10:01 db.opt-rw-r----- 1 mysql mysql 8556 Nov 22 11:48 t1.frm-rw-r----- 1 mysql mysql 98304 Nov 22 11:48 t1.ibd
[root@admin-db12 test]# rm -rf *
[root@admin-db12 test]# ll
total 0
3.查詢驗證數據
在數據庫層,查看當前表中數據,發現當前表數據目前已空空如也。
#當前實例
mysql> select * from t1;
Empty set (0.00 sec)
4.OS層獲取內存中的數據
當前實例沒有關閉的情況下,查看實例pid。
[root@admin-db62 test]# ps aux | grep 3303
root 21952 0.0 0.0 113304 1648 ? S 11:47 0:00 /bin/sh /mysql/dba/mysql/multi/3303/private/bin/mysqld_safe --defaults-file=/mysql/dba/mysql/multi/3303/etc/my.cnf
mysql 23356 0.2 1.1 19529408 1568416 ? Sl 11:47 0:04 /mysql/dba/mysql/multi/3303/private/bin/mysqld --defaults-file=/mysql/dba/mysql/multi/3303/etc/my.cnf --basedir=/mysql/dba/mysql/multi/3303/private --datadir=/mysql/dba/mysql/multi/3303/data --plugin-dir=/mysql/dba/mysql/multi/3303/private/lib/plugin --user=mysql --log-error=/mysql/dba/mysql/multi/3303/log/mysql-error.log --open-files-limit=65535 --pid-file=/mysql/dba/mysql/multi/3303/pid/mysql.pid --socket=/mysql/dba/mysql/multi/3303/socket/mysql.sock --port=3303
[root@admin-db62 fd]# cd /proc/23356/fd
[root@admin-db62 fd]# ll
lrwx------ 1 root root 64 Nov 22 11:52 39 -> /mysql/dba/mysql/multi/3303/data/mysql/time_zone.ibdlrwx------ 1 root root 64 Nov 22 11:52 4 -> /mysql/dba/mysql/multi/3303/data/ib_logfile0lrwx------ 1 root root 64 Nov 22 11:52 40 -> /mysql/dba/mysql/multi/3303/data/mysql/time_zone_transition.ibdlrwx------ 1 root root 64 Nov 22 11:52 42 -> /mysql/dba/mysql/multi/3303/data/test/t1.ibd (deleted)
通過上述操作我們發現,被我們干掉的數據文件顯示狀態為”deleted“,被刪除。
5.獲取處理數據
為保護好當前服務器現場、在另一臺服務器上開始恢復數據。
#目標端
[root@admin-db64 3306]# nc -l 13306 > /mysql/dba/mysql/multi/3306/data/t1.ibd #db64這臺服務器上,3306實例中來恢復上述被刪除的數據。/mysql/dba/mysql/multi/3306/data為臨時存放數據目錄
#源端
lrwx------ 1 root root 64 Nov 22 11:52 42 -> /mysql/dba/mysql/multi/3303/data/test/t1.ibd (deleted)
[root@admin-db62 fd]# cat 42 | nc 10.26.65.74 13306
#如上操作,將在OS層,內存里的數據拷貝并傳輸至遠程恢復服務器上。
【注意】不要在本機進行恢復、保留線上環境,避免二次傷害。
6.恢復數據處理
在源端服務器進行數據恢復操作。
[root@admin-db64 3306]# nc -l 13306 > /mysql/dba/mysql/multi/3306/data/t1.ibd
[root@admin-db64 3306]# cd data/
[root@admin-db64 data]# ll
total 100
-rw-r----- 1 mysql mysql 67 Nov 22 12:36 db.opt-rw-r--r-- 1 root root 98304 Nov 22 12:37 t1.ibd
[root@admin-db64 data]# chown -R mysql.mysql t1.ibd #更改屬主
登錄源端進行恢復實例操作:
mysql > use test;
Database changed
mysql> show tables;
Empty set (0.00 sec)
#1、根據表結構創建表(不要告訴我表結構也已經沒有了...)
CREATE TABLE `t1` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
#2、discard 表空間
mysql> alter table t1 discard tablespace;
Query OK, 0 rows affected, 1 warning (0.01 sec)
#3、將上面準備好的數據文件放入正確目錄
[root@admin-db64 data]#mv t1.ibd test/
#4、import 表空間
mysql> alter table t1 import tablespace;
Query OK, 0 rows affected, 1 warning (0.01 sec)
#5、查看數據是否可以正常查看
mysql> select * from t1;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+------+
5 rows in set (0.00 sec)
通過上述步驟的操作,發現數據已經可以正常查看,后面只需要將其備份出來,恢復到待恢復實例即可。此處不再贅述。
寫在最后
今天跟大家分享了一種誤刪數據文件利用內存數據恢復的方法,其實還有一些其他的恢復方法,需要根據不同場景去選取最優的處理方案。
最后,需要跟大家強調的是:預防遠比處理的意義大得多。
另外,在 MySQL 的集群方案中,會時不時地用到備份來恢復實例,因此定期檢查備份的有效性也很有必要。如果你是業務開發同學,你可以用 show grants 命令查看賬戶的權限,如果權限過大,可以建議 DBA 同學給你分配權限低一些的賬號;你也可以評估業務的重要性,和 DBA 商量備份的周期、是否有必要創建延遲復制的備庫等等。
記住,數據和服務的可靠性不止是運維團隊的工作,最終是各個合作環節一起保障的結果。