前言
使用數(shù)據(jù)庫過程中難免有出錯的時候,假如不小心刪除了一張表醋安,或者錯誤執(zhí)行了update語句召夹,那么這個時候想要恢復數(shù)據(jù)就需要用到數(shù)據(jù)閃回工具宝当,如:binlog2sql和myflash等审胚。但因為binlog2sql工具要求數(shù)據(jù)庫在線荚坞,即需要連接數(shù)據(jù)庫進行binlog解析才能轉換為sql,無法直接對binlog文件進行解析菲盾,使用條件上相對苛刻,所以沒有考慮各淀。
介紹
myflash是美團研發(fā)的一款開源的數(shù)據(jù)庫閃回工具懒鉴,他可以用來回滾DML操作。
使用條件
- MySQL數(shù)據(jù)庫必須開啟binlog
- binlog格式必須為row,且binlog_row_image=full
- 僅支持5.6與5.7
- 只能回滾DML(增碎浇、刪临谱、改)
下載與安裝
下載地址為:https://github.com/Meituan-Dianping/MyFlash
按照下圖方式下載,可以不用安裝git奴璃。
首先要安裝編譯所必須的依賴包
[root@hadoop101 /]# yum install -y gcc pkg-config glib2 libgnomeui-devel
將壓縮包上傳到服務器后使用unzip命令解壓悉默。
[root@hadoop101 package]# pwd
/opt/package
[root@hadoop101 package]# ls
myflash-master.zip mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz
[root@hadoop101 package]# unzip -d /opt/ myflash-master.zip
...解壓文件列表過長不展示
[root@hadoop101 MyFlash-master]# cd /opt/MyFlash-master/
[root@hadoop101 MyFlash-master]# ls
binary binlog_output_base.flashback build.sh doc License.md README.md source testbinlog
如果下載的是zip包,他會有一個編譯好的程序為解壓路徑/binary/flashback
苟穆,也可以再次編譯抄课,進入解壓后的目錄唱星,編譯并安裝
[root@hadoop101 MyFlash-master]# gcc -w `pkg-config --cflags --libs glib-2.0` source/binlogParseGlib.c -o binary/flashback
安裝完之后是沒有環(huán)境變量的,只能使用絕對路徑調用工具跟磨,使用--help
可以查看命令的使用方式
[root@hadoop101 binary]# /opt/MyFlash-master/binary/flashback --help
Usage:
flashback [OPTION?]
Help Options:
-h, --help Show help options
Application Options:
--databaseNames databaseName to apply. if multiple, seperate by comma(,)
--tableNames tableName to apply. if multiple, seperate by comma(,)
--start-position start position
--stop-position stop position
--start-datetime start time (format %Y-%m-%d %H:%M:%S)
--stop-datetime stop time (format %Y-%m-%d %H:%M:%S)
--sqlTypes sql type to filter . support INSERT, UPDATE ,DELETE. if multiple, seperate by comma(,)
--maxSplitSize max file size after split, the uint is M
--binlogFileNames binlog files to process. if multiple, seperate by comma(,)
--outBinlogFileNameBase output binlog file name base
--logLevel log level, available option is debug,warning,error
--include-gtids gtids to process
--exclude-gtids gtids to skip
參數(shù)解釋间聊,這里我直接借用了別人的,有些東西我也沒用過抵拘,所以不確保是否可用哎榴。
參數(shù) | 釋義 |
---|---|
--databaseNames | 需要閃回的數(shù)據(jù)庫名稱,如果有多個數(shù)據(jù)庫僵蛛,用逗號”尚蝌,”隔開。 |
--tableNames | 要閃回的表名稱充尉,如果有多個表飘言,用逗號”,”隔開。 |
--start-position | 閃回的起始位置喉酌,如不指定热凹,從文件開始處回滾。 |
--stop-position | 閃回的終止位置泪电,如不指定般妙,回滾到文件結尾。 |
--start-datetime | 閃回的開始時間相速。 |
--stop-datetime | 閃回的終止時間碟渺。 |
--sqlTypes | 指定需要回滾的sql類型,支持INSERT突诬、UPDATE苫拍、DELETE,多個類型使用逗號”,”分開旺隙。 |
--maxSplitSize | 對文件進行固定尺寸的切割绒极,以防止單次應用binlog尺寸較大,對線上造成壓力蔬捷。 |
--binlogFileNames | 指定需要回滾的binlog文件垄提,美團文檔說目前只支持單個binlog文件,經(jīng)測試已經(jīng)支持多個binlog文件同時閃回周拐。 |
--outBinlogFileNameBase | 指定輸出的binlog文件前綴铡俐,如不指定,則默認為binlog_output_base.flashback妥粟。 |
logLevel | 僅供開發(fā)者使用审丘,默認級別為error級別。在生產(chǎn)環(huán)境中不要修改這個級別勾给,否則輸出過多滩报。 |
include-gtids | 指定需要回滾的gtid,支持gtid的單個和范圍兩種形式锅知。 |
exclude-gtids | 指定不需要回滾的gtid,用法同include-gtids露泊。 |
事先準備
首先我準備了一個單節(jié)點的mysql喉镰,然后刷新了binlog,之后會建表寫入演示數(shù)據(jù)惭笑,然后模擬誤操作再演示回滾數(shù)據(jù)侣姆。
mysql> flush logs;
Query OK, 0 rows affected (0.02 sec)
mysql> show master status ;
+------------------+----------+--------------+------------------+--------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+--------------------------------------------+
| mysql-bin.000005 | 194 | | | 2ec63aca-cd00-11ec-ba97-000c29648fd7:1-144 |
+------------------+----------+--------------+------------------+--------------------------------------------+
1 row in set (0.00 sec)
mysql> create database demo;
Query OK, 1 row affected (0.00 sec)
mysql> create table `time`(
-> `id` int primary key auto_increment,
-> `string` varchar(50),
-> `create_time` datetime
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into demo.`time` values(null,'!@#',now());
Query OK, 1 row affected (0.01 sec)
mysql> insert into demo.`time` values(null,'*&^',now());
Query OK, 1 row affected (0.00 sec)
mysql> insert into demo.`time` values(null,'^%$',now());
Query OK, 1 row affected (0.00 sec)
mysql> select * from demo.`time`;
+----+--------+---------------------+
| id | string | create_time |
+----+--------+---------------------+
| 1 | !@# | 2022-05-06 17:21:48 |
| 2 | *&^ | 2022-05-06 17:21:53 |
| 3 | ^%$ | 2022-05-06 17:21:58 |
+----+--------+---------------------+
3 rows in set (0.00 sec)
刪除數(shù)據(jù)
此時刪除整張表的數(shù)據(jù),但保留表結構沉噩,一般誤操作都是在圖形化界面誤操作的捺宗,所以我這里使用navicat模擬刪除。
這里千萬不要點刪除表或者截斷表川蒙,刪除表的命令的drop
蚜厉,截斷表的命令是truncate
,這兩個都是DDL語句畜眨,binlog是不會記錄詳細的刪除信息的昼牛,一旦執(zhí)行操作將無法回滾,是myflash無法拯救的康聂。
此時可以查看一下mysql的binlog文件贰健,看看binlog的情況。
[root@hadoop101 binlog]# pwd
/data/mysql_data/binlog
[root@hadoop101 binlog]# ls
mysql-bin.000001 mysql-bin.000002 mysql-bin.000003 mysql-bin.000004 mysql-bin.000005 mysql-bin.index
[root@hadoop101 binlog]# /opt/mysql_6033/bin/mysqlbinlog -vv --base64-output=DECODE-ROWS mysql-bin.000005
......
create database demo
/*!*/;
# at 353
......
create table `time`( `id` int primary key auto_increment, `string` varchar(50), `create_time` datetime )
/*!*/;
# at 596
......
# at 865
#220506 17:21:48 server id 1000 end_log_pos 914 CRC32 0x305f5f15 Write_rows: table id 112 flags: STMT_END_F
### INSERT INTO `demo`.`time`
### SET
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2='!@#' /* VARSTRING(200) meta=200 nullable=1 is_null=0 */
### @3='2022-05-06 17:21:48' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
# at 914
......
# at 1214
#220506 17:21:53 server id 1000 end_log_pos 1263 CRC32 0x834574e8 Write_rows: table id 112 flags: STMT_END_F
### INSERT INTO `demo`.`time`
### SET
### @1=2 /* INT meta=0 nullable=0 is_null=0 */
### @2='*&^' /* VARSTRING(200) meta=200 nullable=1 is_null=0 */
### @3='2022-05-06 17:21:53' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
......
# at 1563
#220506 17:21:58 server id 1000 end_log_pos 1612 CRC32 0xa58ebd4d Write_rows: table id 112 flags: STMT_END_F
### INSERT INTO `demo`.`time`
### SET
### @1=3 /* INT meta=0 nullable=0 is_null=0 */
### @2='^%$' /* VARSTRING(200) meta=200 nullable=1 is_null=0 */
### @3='2022-05-06 17:21:58' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
......
#220506 17:22:24 server id 1000 end_log_pos 1951 CRC32 0xc374eb11 Delete_rows: table id 112 flags: STMT_END_F
### DELETE FROM `demo`.`time`
### WHERE
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2='!@#' /* VARSTRING(200) meta=200 nullable=1 is_null=0 */
### @3='2022-05-06 17:21:48' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
### DELETE FROM `demo`.`time`
### WHERE
### @1=2 /* INT meta=0 nullable=0 is_null=0 */
### @2='*&^' /* VARSTRING(200) meta=200 nullable=1 is_null=0 */
### @3='2022-05-06 17:21:53' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
### DELETE FROM `demo`.`time`
### WHERE
### @1=3 /* INT meta=0 nullable=0 is_null=0 */
### @2='^%$' /* VARSTRING(200) meta=200 nullable=1 is_null=0 */
### @3='2022-05-06 17:21:58' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
# at 1951
......
多余的內容我用省略號代替了恬汁,主要是想展示在binlog中包含了所有有價值的內容伶椿,比如建表,insert和delete氓侧,而且對整張表執(zhí)行delete
命令時脊另,他會一條一條數(shù)據(jù)刪除,刪除的每條數(shù)據(jù)都完好的保存在binlog中约巷,這也為回滾提供了便捷偎痛。
回滾
使用myfalsh工具對binlog進行回滾,他會生成一個新的以.flashback
為后綴的文件独郎,這是一個已經(jīng)回滾完的binlog文件看彼,上面binlog中的delete語句會被轉換為insert語句,然后使用mysqlbinlog命令就可以導入此文件到mysql實例中囚聚,如此便完成回滾。
執(zhí)行命令:
[root@hadoop101 binlog]# /opt/MyFlash-master/binary/flashback --databaseNames="demo" --tableNames="time" --start-datetime="2022-05-06 17:00:00" --stop-datetime="2022-05-06 18:00:00" --sqlTypes="UPDATE,DELETE" --binlogFileNames=/data/mysql_data/binlog/mysql-bin.000005 --outBinlogFileNameBase=/tmp/rollbak.sql
命令中要回滾的數(shù)據(jù)庫為demo标锄,要回滾的表是time顽铸,誤操作的開始時間,即回滾開始時間為2022-05-06 17:00:00料皇,回滾結束時間為2022-05-06 18:00:00谓松,要回滾的語句指定為UPDATE和DELETE星压,要解析的binlog文件是mysql-bin.000005,回滾后的文件保存在/tmp/下鬼譬,文件名前綴為rollbak.sql娜膘。如果有多個數(shù)據(jù)庫和多張表記得用逗號隔開。
然后會在/tmp/
路徑下生成一個叫rollbak.sql.flashback
的文件优质,該文件使用mysqlbinlog命令解析后如下圖
最后將此文件導入即可:
[root@hadoop101 binlog]# /opt/mysql_6033/bin/mysqlbinlog --skip-gtids /tmp/rollbak.sql.flashback | /opt/mysql_6033/bin/mysql -h 127.0.0.1 -P 6033 -u root -p
這里注意竣贪,如果mysql數(shù)據(jù)庫使用了gtid,則導入回滾數(shù)據(jù)時要添加--skip-gtids
的參數(shù)巩螃,否則會報錯演怎。
最后登錄數(shù)據(jù)庫查看
額外的內容
insert和delete的回滾很容易,兩者的操作是相悖的避乏,只需要直接替換關鍵詞即可爷耀,而update是特殊的,在某些場景下不建議在--sqlTypes
參數(shù)中添加UPDATE拍皮。
比如原字段A的值是1歹叮,現(xiàn)將其改為99,那么在binlog中會記錄下“update table set A=99 where A=1”铆帽,如果將其回滾咆耿,這條語句就會變成“update table set A=1 where A=99”,而如果在誤操作delete之間有正常的update锄贼,那么回滾之后數(shù)據(jù)就會異常票灰,正常應該執(zhí)行的update語句被回滾回去了。
所以一定要清楚自己的誤操作到底操作了什么宅荤,針對誤操作的類型進行單獨的回滾是比較好的屑迂。