binlog2sql之MySQL數據閃回

   DBA或開發人員,有時會誤刪或者誤更新數據,如果是線上環境並且影響較大,就需要能快速回滾。傳統恢復方法是利用備份重搭實例,再應用去除錯誤sql後的binlog來恢復數據。此法費時費力,甚至需要停機維護,並不適合快速回滾。也有團隊利用LVM快照來縮短恢復時間,但快照的缺點是會影響mysql的性能。現在有不少好用而且效率又高的開源閃回工具如binlog2sql、mysqlbinlog_flashback,這些工具在工作中給DBA減輕了不少痛苦,以下針對binlog2sql的使用進行實踐演練。

 

binlog2sql的用途:

  • 數據快速回滾(閃回)

  • 主從切換後數據不一致的修復

  • 從binlog生成標準SQL,帶來的衍生功能

安裝binlog2sql前先安裝git和pip:

yum -y install epel-release 
yum -y install git  python-pip
git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql
pip install -r requirements.txt

 MySQL的配置要開啓以下選項:

mysqld]
server_id = 1log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 1G
binlog_format = row
binlog_row_image = full

要授權一個用戶有以下權限:

SELECT, REPLICATION SLAVE, REPLICATION CLIENT

權限說明:

  • select:需要讀取server端information_schema.COLUMNS表,獲取表結構的元信息,拼接成可視化的sql語句

  • super/replication client:兩個權限都可以,需要執行'SHOW MASTER STATUS', 獲取server端的binlog列表

  • replication slave:通過BINLOG_DUMP協議獲取binlog內容的權限

 

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   |
+---------------+-------+
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 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
row in set (0.00 sec)

mysql> select * from tb1;
+------+------+
| id   | name |
+------+------+
|    1 | aa   |
|    2 | bb   |
+------+------+
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     |
+------+--------+
rows in set (0.00 sec)

mysql>

下面我們使用binlog2sql進行格式爲ROW的binlog生成標準SQL,帶個-d的參數指定庫名:

[root@db_server ~]#python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi --start-file='mysql-bin.000107' > xuanzhi.sql 
[root@db_server ~]#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 ~]#

我們可以看到,剛剛執行過的sql都生成出來了。

我們現在對xuanzhi這個庫的所有操作生成反向SQL,這個時候需要在上面語句的基礎上帶一個-B參數,就是flashback閃回的意思:

[root@db_server ~]#python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi --start-file='mysql-bin.000107' > xuanzhi.sql 
[root@db_server ~]#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 ~]#

我們可以看到,剛剛執行過的sql都生成出來了。

我們現在對xuanzhi這個庫的所有操作生成反向SQL,這個時候需要在上面語句的基礎上帶一個-B參數,就是flashback閃回的意思:

[root@db_server ~]#python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi --start-file='mysql-bin.000107' -B  > rollback_xuanzhi.sql
[root@db_server ~]#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   |
+----+------+
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   |
+----+------+
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 ~]# python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi -ttb1 --start-file='mysql-bin.000109' -B  > rollback_tb1.sql 
[root@db_server ~]# cat rollback_tb1.sql 
INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (4, 'dd'); #start 4 end 298 time 2017-03-23 12:39:20INSERT 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   |
+----+------+
rows in set (0.00 sec)

mysql>

可以看到數據可以正常的恢復。

 

模擬二:誤操作把一個表的數據刪除了,經常出現的就是delete沒帶where條件

mysql> select * from tb1;
+----+------+
| id | name |
+----+------+
|  1 | aa   |
|  2 | bb   |
|  3 | cc   |
|  4 | dd   |
+----+------+
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 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
row in set (0.00 sec)

mysql>

我們用bin2log對這個表進行恢復:

[root@db_server ~]# python binlog2sql.py -uflashuser -h127.0.0.1 -pflash123 -dxuanzhi -ttb1 --start-file='mysql-bin.000110' -B  > rollback_tb1.sql  
[root@db_server ~]# cat rollback_tb1.sql 
INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (4, 'dd'); #start 4 end 314 time 2017-03-23 13:37:29INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (3, 'cc'); #start 4 end 314 time 2017-03-23 13:37:29INSERT INTO `xuanzhi`.`tb1`(`id`, `name`) VALUES (2, 'bb'); #start 4 end 314 time 2017-03-23 13:37:29INSERT 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盤):

645933-20170323164043471-1602129100.png


參考文章:

https://github.com/danfengcao/binlog2sql

https://github.com/danfengcao/binlog2sql/blob/master/example/mysql-flashback-priciple-and-practice.md

 

總結:一、線上要對程序做好最小化權限控制,這樣可以減少很多不必要的麻煩。

        二、現在開源比較好用的數據閃回工具有mysqlbinlog_flashbackbinlog2sql,給DBA日常維護帶來了許多幫助。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章