MySQL誤操做後如何快速恢復數據

基本上每一個跟數據庫打交道的程序員(固然也多是你同事)都會碰一個問題,MySQL誤操做後如何快速回滾?好比,不當心update了整張表的某個字段,或者delete一張表,忘加限制條件,整張表都沒了。假如這仍是線上環境核心業務數據,那這事就鬧大了。誤操做後,能快速回滾數據是很是重要的。php

傳統解法

用全量備份重搭實例,再利用增量binlog備份,恢復到誤操做以前的狀態。而後跳過誤操做的SQL,再繼續應用binlog。對於DML的回滾,此法費時費力,不值得再推薦。html

利用binlog2sql快速閃回

首先,確認你的MySQL server開啓了binlog,設置瞭如下參數:python

[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 100M
binlog-format = row

若是沒有開啓binlog,也沒有預先生成回滾SQL,那真的沒法快速回滾了。對存放重要業務數據的MySQL,強烈建議開啓binlog。mysql

隨後,安裝開源工具binlog2sql。binlog2sql是一款簡單易用的binlog解析工具,其中一個功能就是生成回滾SQL。git

shell> git clone https://github.com/danfengcao/binlog2sql.git
shell> pip install -r requirements.txt

而後,咱們就能夠生成回滾SQL了。程序員

背景:小明在20點多時誤刪了test庫tbl表整張表的數據,須要緊急回滾。github

test庫tbl表原有數據
mysql> select * from tbl;
+----+--------+---------------------+
| id | name   | addtime             |
+----+--------+---------------------+
|  1 | 小趙   | 2016-12-10 00:04:33 |
|  2 | 小錢   | 2016-12-10 00:04:48 |
|  3 | 小孫   | 2016-12-13 20:25:00 |
|  4 | 小李   | 2016-12-12 00:00:00 |
+----+--------+---------------------+
4 rows in set (0.00 sec)

mysql> delete from tbl;
Query OK, 4 rows affected (0.00 sec)

20:28時,tbl表誤操做被清空
mysql> select * from tbl;
Empty set (0.00 sec)

恢復數據步驟sql

  1. 登陸mysql,查看目前的binlog文件shell

     

mysql> show master status; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000051 | 967 | | mysql-bin.000052 | 965 | +------------------+-----------+數據庫

2. 最新的binlog文件是mysql-bin.000052,咱們再定位誤操做SQL的binlog位置。誤操做人只能知道大體的誤操做時間,咱們根據大體時間過濾數據。

	```bash
shell> python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000052' --start-datetime='2016-12-13 20:25:00' --stop-datetime='2016-12-13 20:30:00'
輸出:
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-13 20:25:00', 3, '小孫'); #start 4 end 290 time 2016-12-13 20:25:46
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-13 20:26:00', 4, '小李'); #start 317 end 487 time 2016-12-13 20:26:26
UPDATE `test`.`tbl` SET `addtime`='2016-12-12 00:00:00', `id`=4, `name`='小李' WHERE `addtime`='2016-12-13 20:26:00' AND `id`=4 AND `name`='小李' LIMIT 1; #start 514 end 701 time 2016-12-13 20:27:07
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:33' AND `id`=1 AND `name`='小趙' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:48' AND `id`=2 AND `name`='小錢' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-13 20:25:00' AND `id`=3 AND `name`='小孫' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-12 00:00:00' AND `id`=4 AND `name`='小李' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
  1. 咱們獲得了誤操做sql的準確位置在728-938之間,再根據位置過濾,使用flashback模式生成回滾sql,檢查回滾sql是否正確(注:真實環境下,此步常常會進一步篩選出須要的sql。結合grep、編輯器等)

     

shell> python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000052' --start-position=3346 --stop-position=3556 -B > rollback.sql | cat 輸出: INSERT INTO test.tbl(addtime, id, name) VALUES ('2016-12-12 00:00:00', 4, '小李'); #start 728 end 938 time 2016-12-13 20:28:05 INSERT INTO test.tbl(addtime, id, name) VALUES ('2016-12-13 20:25:00', 3, '小孫'); #start 728 end 938 time 2016-12-13 20:28:05 INSERT INTO test.tbl(addtime, id, name) VALUES ('2016-12-10 00:04:48', 2, '小錢'); #start 728 end 938 time 2016-12-13 20:28:05 INSERT INTO test.tbl(addtime, id, name) VALUES ('2016-12-10 00:04:33', 1, '小趙'); #start 728 end 938 time 2016-12-13 20:28:05

4. 確認回滾sql正確,執行回滾語句。登陸mysql確認,數據回滾成功。

	```bash
	shell> mysql -h127.0.0.1 -P3306 -uadmin -p'admin' < rollback.sql

	mysql> select * from tbl;
+----+--------+---------------------+
| id | name   | addtime             |
+----+--------+---------------------+
|  1 | 小趙   | 2016-12-10 00:04:33 |
|  2 | 小錢   | 2016-12-10 00:04:48 |
|  3 | 小孫   | 2016-12-13 20:25:00 |
|  4 | 小李   | 2016-12-12 00:00:00 |
+----+--------+---------------------+

至此,不用再擔憂被炒魷魚了。

常見問題

  • 有人會問,我DDL誤操做了怎麼快速回滾?好比drop了一張大表。

很難作到。由於即便在在row模式下,DDL操做也不會把每行數據的變化記錄到binlog,因此DDL沒法經過binlog回滾。實現DDL回滾,必需要在執行DDL前先備份老數據。確實有人經過修改mysql server源碼實現了DDL的快速回滾,我找到阿里的xiaobin lin提交了一個patch。但據我所知,國內不多有互聯網公司應用了這個特性。緣由的話,我認爲最主要仍是懶的去折騰,不必搞這個低頻功能,次要緣由是會增長一些額外存儲。

因此,DDL誤操做的話通常只能經過備份來恢復。若是公司連備份也不能用了,那真的建議去買張飛機票了。幹啥?跑唄

  • mysql除了binlog2sql,是否還有其餘回滾工具?

    固然有。阿里彭立勳對mysqlbinlog增長了flashback的特性,這應該是mysql最先有的flashback功能,彭解決的是DML的回滾,並說明了利用binlog進行DML閃回的設計思路。DDL回滾特性也是由阿里團隊提出並實現的。這兩個功能是有創新精神的,此後出現的閃回工具基本都是對上面二者的模仿。另外,去哪兒開源的Inception是一套MySQL自動化運維工具,這個就比較重了,支持DML回滾,還不是從binlog回滾的,是從備份回滾的,也支持DDL回滾表結構,數據是回滾不了滴~ 還有一種作法叫slave延時備份,搞臺不加業務流量的slave,故意延遲一段時間,這實際上是在傳統辦法的基礎上去除了實例恢復這步。此法會額外消耗一臺機器,咱們不推薦這麼作。

若有mysql回滾相關的優秀工具優秀文章遺漏,煩請告知。

個人郵箱 danfengcao.info@gmail.com

參考資料

[1] 彭立勳, MySQL下實現閃回的設計思路

[2] Lixun Peng, Provide the flashback feature by binlog

[3] 丁奇, MySQL閃回方案討論及實現

[4] xiaobin lin, flashback from binlog for MySQL

[5] 王竹峯, 去哪兒inception

[6] danfengcao, binlog2sql: Parse MySQL binlog to SQL you want

相關文章
相關標籤/搜索