1. 程式人生 > 實用技巧 >誤刪除innodb ibdata資料檔案

誤刪除innodb ibdata資料檔案

今天在群裡看到有人說不熟悉innodb把ibdata(資料檔案)和ib_logfile(事務日誌)檔案誤刪除了。不知道怎麼解決。當時我也不知道怎麼辦。後來查閱相關資料。終找到解決方法。其實恢復也挺簡單的。我們不知道的時候就覺得難了。誰說不是這樣呢?

下面我們就來模擬生產環境下,人為刪除資料檔案和重做日誌檔案。然後詳細說明恢復步驟。

1.用sysbench模擬資料的寫入,如下所示:

[root@yayun-mysql-server ~]# sysbench --test=oltp --oltp-table-size=1000000 --oltp-read-only=off --init-rng=on --num-threads=16 --max-requests=0 --oltp-dist-type=uniform --max-time=1800 --mysql-user=root --mysql-socket=/tmp/mysqld.sock --mysql-password=123456 --db-driver=mysql --mysql-table-engine=innodb --oltp-test-mode=complex prepare      
sysbench 0.4.10:  multi-threaded system evaluation benchmark

Creating table 'sbtest'...
Creating 1000000 records in table 'sbtest'...

2.使用命令rm -f ib*刪除資料檔案和事務日誌檔案:

[root@yayun-mysql-server mysql]# ls
employees    ib_logfile1       mysql-bin.000003  mysql-bin.000008  performance_schema  world_innodb                  yayun-mysql-server.pid
general.log  menagerie         mysql-bin.000004  mysql-bin.000009  sakila              world_myisam
host         mysql             mysql-bin.000005  mysql-bin.000010  sbtest              xtrabackup_binlog_pos_innodb
ibdata1      mysql-bin.000001  mysql-bin.000006  mysql-bin.index   slow-query.log      yayun
ib_logfile0  mysql-bin.000002  mysql-bin.000007  percona           test                yayun-mysql-server.err
[root@yayun-mysql-server mysql]# rm -f ib*
[root@yayun-mysql-server mysql]# 

下面我們來看看如何恢復:

若此時發現數據庫還能正常工作,資料依然可讀可寫,切記:這個時候千萬不要把mysqld程序殺死,否則真沒法挽救了,你就等著哭吧。

(root@yayun 20:42:25pm> ) [yayun]>select * from t1;
+----+-------+
| id | name  |
+----+-------+
|  1 | yayun |
|  2 | atlas |
|  3 | mysql |
+----+-------+
3 rows in set (0.00 sec)

(root@yayun 20:42:28pm> ) [yayun]>insert into t1 select 4,'python';
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

(root@yayun 20:42:48pm> ) [yayun]>select * from t1;                
+----+--------+
| id | name   |
+----+--------+
|  1 | yayun  |
|  2 | atlas  |
|  3 | mysql  |
|  4 | python |
+----+--------+
4 rows in set (0.00 sec)

(root@yayun 20:42:50pm> ) [yayun]>

我這裡讀寫都正常。所以我們能夠恢復成功的。
(1)首先,先找到mysqld程序的pid,如下所示:

[root@yayun-mysql-server ~]# netstat -nltp | grep mysqld
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      5725/mysqld         
[root@yayun-mysql-server ~]# 

可見mysqld的pid是5725,這一步是關鍵的一步。

(2)使用如下命令檢視結果(非常重要)

[root@yayun-mysql-server ~]# ll /proc/5725/fd | egrep 'ib_|ibdata'
lrwx------. 1 root root 64 Apr 30 20:44 10 -> /data/mysql/ib_logfile1 (deleted)
lrwx------. 1 root root 64 Apr 30 20:44 4 -> /data/mysql/ibdata1 (deleted)
lrwx------. 1 root root 64 Apr 30 20:44 9 -> /data/mysql/ib_logfile0 (deleted)
[root@yayun-mysql-server ~]# 

這裡有相關很重要的知識,童鞋們自行查閱,刪除一個檔案時,並不是真正刪除,而是打一個標記,同樣在我們mysql資料庫中,delete一條記錄實際的刪除操作也沒有發生。
上面顯示的結果中,其中10,4,9就是我們需要恢復的檔案。

(3)在恢復檔案前,需要執行flush tables with read lock,確保資料庫沒有寫入操作,以便我們完成恢復

(root@yayun 20:55:26pm> ) [(none)]>flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

(root@yayun 20:55:31pm> ) [(none)]>

那麼我們如何確定沒有資料寫入呢?分幾個步驟檢視

(1)設定髒頁重新整理比例(讓髒頁儘快重新整理到磁碟)

(root@yayun 20:55:31pm> ) [(none)]>set global innodb_max_dirty_pages_pct=0;
Query OK, 0 rows affected (0.00 sec)

(root@yayun 20:57:42pm> ) [(none)]>

(2)檢視binlog日誌寫入情況,確保File和Position的值沒有發生變化

(root@yayun 20:57:42pm> ) [(none)]>show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000010 | 61704130 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

(root@yayun 20:59:11pm> ) [(none)]>

(3)檢視innodb狀態資訊,確保髒頁已經重新整理到磁碟

(root@yayun 20:59:11pm> ) [(none)]>show engine innodb status\G
------------
TRANSACTIONS
------------
Trx id counter B9E0F
Purge done for trx's n:o < B9E0C undo n:o < 0    #確保後臺執行緒purge把undo log全部清刷掉

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 2543, seg size 2545, 0 merges  #確保合併插入快取等於1

---
LOG
---
Log sequence number 6173930288
Log flushed up to   6173930288            #確保這裡三個值保持一致,並且不再變化
Last checkpoint at  6173930288

Buffer pool size   65534
Free buffers       50513
Database pages     15020
Old database pages 5506
Modified db pages  0                       #確保髒頁數量為0

--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread process no. 5725, id 140014471358208, state: waiting for server activity
Number of rows inserted 1000004, updated 1995, deleted 0, read 2008
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s           #確保插入,更新,刪除為0

上面我們都確認後,就可以進行恢復操作了。記得前面我們檢視要恢復的檔案的命令吧,我們的mysqld程序的pid是5725,我們再次看看需要恢復的檔案

[root@yayun-mysql-server ~]# ll /proc/5725/fd | egrep 'ib_|ibdata'
lrwx------. 1 root root 64 Apr 30 20:44 10 -> /data/mysql/ib_logfile1 (deleted)
lrwx------. 1 root root 64 Apr 30 20:44 4 -> /data/mysql/ibdata1 (deleted)
lrwx------. 1 root root 64 Apr 30 20:44 9 -> /data/mysql/ib_logfile0 (deleted)
[root@yayun-mysql-server ~]# 

把10,4,9檔案cp到原來mysql的資料目錄下:

[root@yayun-mysql-server ~]# cd /proc/5725/fd
[root@yayun-mysql-server fd]# cp 10 /data/mysql/ib_logfile1
[root@yayun-mysql-server fd]# cp 4 /data/mysql/ibdata1
[root@yayun-mysql-server fd]# cp 9 /data/mysql/ib_logfile0
[root@yayun-mysql-server fd]# 

修改檔案許可權

[root@yayun-mysql-server ~]# cd /data/mysql
[root@yayun-mysql-server mysql]# chown -R mysql.mysql ib*
[root@yayun-mysql-server mysql]# ll | egrep 'ib_|ibdata1'
-rw-r--r-- 1 mysql mysql 866123776 Apr 30 21:13 ibdata1
-rw-r--r-- 1 mysql mysql  67108864 Apr 30 21:13 ib_logfile0
-rw-r--r-- 1 mysql mysql  67108864 Apr 30 21:11 ib_logfile1
[root@yayun-mysql-server mysql]# 

重啟mysql,修復完成

[root@yayun-mysql-server mysql]# /etc/init.d/mysqld restart
Shutting down MySQL...                                     [  OK  ]
Starting MySQL....                                         [  OK  ]
[root@yayun-mysql-server mysql]# 

注意:生產環境切勿測試,童鞋們可以自己開啟虛擬機器進行測試。