DBA或開發人員,有時會誤刪或者誤更新數據,若是是線上環境而且影響較大,就須要能快速回滾。傳統恢復方法是利用備份重搭實例,再應用去除錯誤sql後的binlog來恢復數據。此法費時費力,甚至須要停機維護,並不適合快速回滾。也有團隊利用LVM快照來縮短恢復時間,但快照的缺點是會影響mysql的性能。如今有很多好用並且效率又高的開源閃回工具如binlog2sql、mysqlbinlog_flashback,這些工具在工做中給DBA減輕了很多痛苦,如下針對binlog2sql的使用進行實踐演練。html
binlog2sql的用途:python
安裝binlog2sql前先安裝git和pip:mysql
yum -y install epel-release
yum -y install git python-pip
安裝binlog2sql:git
git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql
pip install -r requirements.txt
MySQL的配置要開啓如下選項:github
[mysqld] server_id = 1 log_bin = /var/log/mysql/mysql-bin.log max_binlog_size = 1G binlog_format = row binlog_row_image = full
要受權一個用戶有如下權限:sql
SELECT, REPLICATION SLAVE, REPLICATION CLIENT
權限說明:ide
binlog2sql的使用參數說明:工具
mysql鏈接配置性能
-h host; -P port; -u user; -p password測試
解析模式
--stop-never 持續同步binlog。可選。不加則同步至執行命令時最新的binlog位置。
-K, --no-primary-key 對INSERT語句去除主鍵。可選。
-B, --flashback 生成回滾語句,可解析大文件,不受內存限制,每打印一千行加一句SLEEP SELECT(1)。可選。與stop-never或no-primary-key不能同時添加。
解析範圍控制
--start-file 起始解析文件。必須。
--start-position/--start-pos start-file的起始解析位置。可選。默認爲start-file的起始位置。
--stop-file/--end-file 末尾解析文件。可選。默認爲start-file同一個文件。若解析模式爲stop-never,此選項失效。
--stop-position/--end-pos stop-file的末尾解析位置。可選。默認爲stop-file的最末位置;若解析模式爲stop-never,此選項失效。
--start-datetime 從哪一個時間點的binlog開始解析,格式必須爲datetime,如'2016-11-11 11:11:11'。可選。默認不過濾。
--stop-datetime 到哪一個時間點的binlog中止解析,格式必須爲datetime,如'2016-11-11 11:11:11'。可選。默認不過濾。
對象過濾
-d, --databases 只輸出目標db的sql。可選。默認爲空。
-t, --tables 只輸出目標tables的sql。可選。默認爲空。
進行用戶受權操做(這裏只是舉例子):
mysql> GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'flashuser'@'127.0.0.1' identified by 'flash123'; Query OK, 0 rows affected (0.00 sec)
咱們能夠看看如今有的數據:
mysql> show global variables like 'binlog_format'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | binlog_format | ROW | +---------------+-------+ 1 row in set (0.00 sec) mysql> mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000107 | 120 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql> select * from tb1; +------+------+ | id | name | +------+------+ | 1 | aa | | 2 | bb | +------+------+ 2 rows in set (0.00 sec) mysql>
咱們如今進行數據的DML操做:
mysql> insert into tb1 values (3,'cc'); Query OK, 1 row affected (0.00 sec) mysql> insert into tb1 values (4,'dd'); Query OK, 1 row affected (0.00 sec) mysql> update tb1 set name='new_aa' where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> delete from tb1 where id=2; Query OK, 1 row affected (0.00 sec) mysql> select * from tb1; +------+--------+ | id | name | +------+--------+ | 1 | new_aa | | 3 | cc | | 4 | dd | +------+--------+ 3 rows in set (0.00 sec) mysql>
下面咱們使用binlog2sql進行格式爲ROW的binlog生成標準SQL,帶個-d的參數指定庫名:
[root@db_server_xuanzhi ~]#python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi --start-file='mysql-bin.000107' > xuanzhi.sql [root@db_server_xuanzhi ~]#cat xuanzhi.sql INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (3, 'cc'); #start 4 end 290 time 2017-03-23 10:41:34 INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (4, 'dd'); #start 321 end 491 time 2017-03-23 10:41:38 UPDATE `xuanzhi`.`tb1` SET `id`=1, `name`='new_aa' WHERE `id`=1 AND `name`='aa' LIMIT 1; #start 522 end 705 time 2017-03-23 10:41:42 DELETE FROM `xuanzhi`.`tb1` WHERE `id`=2 AND `name`='bb' LIMIT 1; #start 736 end 906 time 2017-03-23 10:41:50 [root@db_server_xuanzhi ~]#
咱們能夠看到,剛剛執行過的sql都生成出來了。
咱們如今對xuanzhi這個庫的全部操做生成反向SQL,這個時候須要在上面語句的基礎上帶一個-B參數,就是flashback閃回的意思:
[root@db_server_xuanzhi ~]#python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi --start-file='mysql-bin.000107' -B > rollback_xuanzhi.sql [root@db_server_xuanzhi ~]#cat rollback_xuanzhi.sql INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (2, 'bb'); #start 736 end 906 time 2017-03-23 10:41:50 UPDATE `xuanzhi`.`tb1` SET `id`=1, `name`='aa' WHERE `id`=1 AND `name`='new_aa' LIMIT 1; #start 522 end 705 time 2017-03-23 10:41:42 DELETE FROM `xuanzhi`.`tb1` WHERE `id`=4 AND `name`='dd' LIMIT 1; #start 321 end 491 time 2017-03-23 10:41:38 DELETE FROM `xuanzhi`.`tb1` WHERE `id`=3 AND `name`='cc' LIMIT 1; #start 4 end 290 time 2017-03-23 10:41:34 [root@db_server_xuanzhi ~]#
能夠看到生成了跟上面標準SQL相反的SQL了,經過這些反向SQL能夠進行誤操的數據恢復。
下面咱們模擬對線上數據進行誤操及恢復的過程:
模擬一:誤操把一個表的某些重要記錄刪除了,進行恢復
咱們把tb1的id>=3的數據刪除:
mysql> select * from tb1; +----+------+ | id | name | +----+------+ | 1 | aa | | 2 | bb | | 3 | cc | | 4 | dd | +----+------+ 4 rows in set (0.00 sec) mysql> delete from tb1 where id >= 3; Query OK, 2 rows affected (0.00 sec) mysql> select * from tb1; +----+------+ | id | name | +----+------+ | 1 | aa | | 2 | bb | +----+------+ 2 rows in set (0.00 sec) mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000109 | 329 | | | | +------------------+----------+--------------+------------------+-------------------+
如今經過binlog2sql進行生成反向SQL,binlog2sql能夠指定生成那個庫的那個表的標準SQL或者反向SQL,帶一個-t的選擇:
[root@db_server_xuanzhi ~]# python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi -ttb1 --start-file='mysql-bin.000109' -B > rollback_tb1.sql [root@db_server_xuanzhi ~]# cat rollback_tb1.sql INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (4, 'dd'); #start 4 end 298 time 2017-03-23 12:39:20 INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (3, 'cc'); #start 4 end 298 time 2017-03-23 12:39:20
咱們能夠看剛剛對tb1進行誤刪的操做,都生成了反向的SQL語句也就是INSERT INTO,咱們進行導入操做,看數據可否正常恢復
[root@db_server_xuanzhi ~]#mysql -uroot -p123456 <./rollback_tb1.sql
Warning: Using a password on the command line interface can be insecure.
[root@db_server_xuanzhi ~]#
登陸查看一下數據:
mysql> select * from tb1; +----+------+ | id | name | +----+------+ | 1 | aa | | 2 | bb | | 3 | cc | | 4 | dd | +----+------+ 4 rows in set (0.00 sec) mysql>
能夠看到數據能夠正常的恢復。
模擬二:誤操做把一個表的數據刪除了,常常出現的就是delete沒帶where條件
mysql> select * from tb1; +----+------+ | id | name | +----+------+ | 1 | aa | | 2 | bb | | 3 | cc | | 4 | dd | +----+------+ 4 rows in set (0.00 sec) mysql> delete from tb1; Query OK, 4 rows affected (0.00 sec) mysql> select * from tb1; Empty set (0.00 sec) mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000110 | 345 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql>
咱們用bin2log對這個表進行恢復:
[root@db_server_xuanzhi ~]# python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi -ttb1 --start-file='mysql-bin.000110' -B > rollback_tb1.sql [root@db_server_xuanzhi ~]# cat rollback_tb1.sql INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (4, 'dd'); #start 4 end 314 time 2017-03-23 13:37:29 INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (3, 'cc'); #start 4 end 314 time 2017-03-23 13:37:29 INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (2, 'bb'); #start 4 end 314 time 2017-03-23 13:37:29 INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (1, 'aa'); #start 4 end 314 time 2017-03-23 13:37:29 [root@db_server_xuanzhi ~]# mysql -uroot -p123456 <./rollback_tb1.sql Warning: Using a password on the command line interface can be insecure.
再查詢一下,數據是否把數據恢復了:
mysql> select * from tb1; Empty set (0.00 sec) <Slave_1>[xuanzhi]> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000110 | 345 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql> select * from tb1; +----+------+ | id | name | +----+------+ | 1 | aa | | 2 | bb | | 3 | cc | | 4 | dd | +----+------+ 4 rows in set (0.00 sec) mysql>
能夠看到能夠正常恢復,但值得注意的是drop table 和truncate table 是沒法生成反向SQL的,因此建議線上程序帳號只給insert,upfate,select,delete權限。
還有不少選項--stop-position/--end-pos stop-file、--start-datetime/--stop-datetime這些選項就不一 一說明了,binlog2sql總的來講仍是比較好用與實用的,之前寫過一篇博客binlog-rollback.pl 的博客,這個腳本也能夠實現,但遇到比較大的binlog就可能會出現一些問題,下面是我在線上測試對1.1G的binlog用binlog2sql進行解析的時間(阿里雲的SSD盤):
參考文章:
https://github.com/danfengcao/binlog2sql
https://github.com/danfengcao/binlog2sql/blob/master/example/mysql-flashback-priciple-and-practice.md
總結:1、線上要對程序作好最小化權限控制,這樣能夠減小不少沒必要要的麻煩。
2、如今開源比較好用的數據閃回工具備mysqlbinlog_flashback和binlog2sql,給DBA平常維護帶來了許多幫助。
做者:陸炫志 出處:xuanzhi的博客 http://www.cnblogs.com/xuanzhi201111 您的支持是對博主最大的鼓勵,感謝您的認真閱讀。本文版權歸做者全部,歡迎轉載,但請保留該聲明。 |