程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQL閃回(flashback)原理與實戰

MySQL閃回(flashback)原理與實戰

編輯:MySQL綜合教程

MySQL閃回(flashback)原理與實戰。本站提示廣大學習愛好者:(MySQL閃回(flashback)原理與實戰)文章只能為提供參考,不一定能成為您想要的結果。以下是MySQL閃回(flashback)原理與實戰正文


DBA或開發人員,有時會誤刪或許誤更新數據,假如是線上環境並且影響較大,就需求能疾速回滾。傳統恢復辦法是應用備份重搭實例,再使用去除錯誤sql後的binlog來恢單數據。此法費時費力,甚至需求停機維護,並不合適疾速回滾。也有團隊應用LVM快照來延長恢復時間,但快照的缺陷是會影響mysql的功能。

MySQL閃回(flashback)應用binlog直接停止回滾,能疾速恢復且不必停機。本文將引見閃回原理,給出筆者的實戰經歷,並對現存的閃回工具作比擬。

開胃菜

某天,小明因種種緣由,誤刪了大批線上用戶表的數據。他急忙找到公司DBA懇求協助,“客服電話已被打爆,少量用戶贊揚無法登陸,指導十分惱火。請問多久能恢單數據?”DBA一臉懵逼,緘默十秒後,伸出一根手指。“你的意思是一分鐘就能恢復?太好了。”小明終於有些抓緊,顯露了一絲愁容。“不,我們中有團體將會分開公司。”DBA沉痛的說道。

勿讓喜劇發作,盡早將此文轉給公司DBA。

閃回原理

binlog概述

MySQL binlog以event的方式,記載了MySQL server從啟用binlog以來一切的變卦信息,可以協助重現這之間的一切變化。MySQL引入binlog次要有兩個目的:一是為了主從復制;二是某些備份復原操作後需求重新使用binlog。

有三種可選的binlog格式,各有優缺陷:

    statement:基於SQL語句的形式,binlog數據量小,但是某些語句和函數在復制進程能夠招致數據不分歧甚至出錯; row:基於行的形式,記載的是行的完好變化。很平安,但是binlog會比其他兩種形式大很多; mixed:混合形式,依據語句來選用是statement還是row形式;

應用binlog閃回,需求將binlog格式設置為row。row形式下,一條運用innodb的insert會發生如下格式的binlog:

# at 1129
#161225 23:15:38 server id 3773306082 end_log_pos 1197     Query  thread_id=1903021    exec_time=0   error_code=0
SET TIMESTAMP=1482678938/*!*/;
BEGIN
/*!*/;
# at 1197
#161225 23:15:38 server id 3773306082 end_log_pos 1245     Table_map: `test`.`user` mapped to number 290
# at 1245
#161225 23:15:38 server id 3773306082 end_log_pos 1352     Write_rows: table id 290 flags: STMT_END_F

BINLOG '
muJfWBPiFOjgMAAAAN0EAAAAACIBAAAAAAEABHRlc3QABHVzZXIAAwMPEQMeAAAC
muJfWB7iFOjgawAAAEgFAAAAACIBAAAAAAEAAgAD//gBAAAABuWwj+i1tVhK1hH4AgAAAAblsI/p
krFYStYg+AMAAAAG5bCP5a2ZWE/onPgEAAAABuWwj+adjlhNeAD4BQAAAAJ0dFhRYJM=
'/*!*/;
# at 1352
#161225 23:15:38 server id 3773306082 end_log_pos 1379     Xid = 5327954
COMMIT/*!*/;

閃回原理

既然binlog以event方式記載了一切的變卦信息,那麼我們把需求回滾的event,從後往前回滾回去即可。

關於單個event的回滾,我們以表test.user來演示原理

mysql> show create table test.user\G
*************************** 1. row ***************************
    Table: user
Create Table: CREATE TABLE `user` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(10) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

關於delete操作,我們從binlog提取出delete信息,生成的回滾語句是insert。(注:為了方便解釋,我們用binlog2sql將原始binlog轉化成了可讀SQL)

 原始:DELETE FROM `test`.`user` WHERE `id`=1 AND `name`='小趙';
 回滾:INSERT INTO `test`.`user`(`id`, `name`) VALUES (1, '小趙');


關於insert操作,回滾SQL是delete。

 原始:INSERT INTO `test`.`user`(`id`, `name`) VALUES (2, '小錢');
 回滾:DELETE FROM `test`.`user` WHERE `id`=2 AND `name`='小錢';


關於update操作,回滾sql應該交流SET和WHERE的值。

 原始:UPDATE `test`.`user` SET `id`=3, `name`='小李' WHERE `id`=3 AND `name`='小孫';
 回滾:UPDATE `test`.`user` SET `id`=3, `name`='小孫' WHERE `id`=3 AND `name`='小李';

閃回實戰

真實的閃回場景中,最關鍵的是能疾速挑選出真正需求回滾的SQL。

我們運用開源工具binlog2sql來停止實戰演練。binlog2sql由美團點評DBA團隊(上海)出品,屢次在線上環境做疾速回滾。

首先我們裝置binlog2sql:

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

背景:小明在11:44時誤刪了test庫user表大批的數據,需求緊急回滾。

test庫user表原無數據

mysql> select * from user;
+----+--------+---------------------+
| id | name  | addtime       |
+----+--------+---------------------+
| 1 | 小趙  | 2013-11-11 00:04:33 |
| 2 | 小錢  | 2014-11-11 00:04:48 |
| 3 | 小孫  | 2016-11-11 20:25:00 |
| 4 | 小李  | 2013-11-11 00:00:00 |
.........
+----+--------+---------------------+
16384 rows in set (0.04 sec)

11:44時,user表大批數據被誤刪除。與此同時,正常業務數據是在持續寫入的

mysql> delete from user where addtime>'2014-01-01';
Query OK, 16128 rows affected (0.18 sec)

mysql> select count(*) from user;
+----------+
| count(*) |
+----------+
|   261 |
+----------+

恢單數據步驟:

登錄mysql,檢查目前的binlog文件

mysql> show master logs;
+------------------+-----------+
| Log_name     | File_size |
+------------------+-----------+
| mysql-bin.000053 | 168652863 |
| mysql-bin.000054 |  504549 |
+------------------+-----------+

最新的binlog文件是mysql-bin.000054。我們的目的是挑選出需求回滾的SQL,由於誤操作人只知道大致的誤操作時間,我們首先依據時間做一次過濾。只需求解析test庫user表。(注:假如有多個sql誤操作,則生成的binlog能夠散布在多個文件,需解析多個文件)

shell> python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -tuser --start-file='mysql-bin.000054' --start-datetime='2016-12-26 11:44:00' --stop-datetime='2016-12-26 11:50:00' > /tmp/raw.sql
raw.sql 輸入:
DELETE FROM `test`.`user` WHERE `addtime`='2014-11-11 00:04:48' AND `id`=2 AND `name`='小錢' LIMIT 1; #start 257427 end 265754 time 2016-12-26 11:44:56
DELETE FROM `test`.`user` WHERE `addtime`='2015-11-11 20:25:00' AND `id`=3 AND `name`='小孫' LIMIT 1; #start 257427 end 265754 time 2016-12-26 11:44:56
...
DELETE FROM `test`.`user` WHERE `addtime`='2016-12-14 23:09:07' AND `id`=24530 AND `name`='tt' LIMIT 1; #start 257427 end 504272 time 2016-12-26 11:44:56
INSERT INTO `test`.`user`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:33', 32722, '小王'); #start 504299 end 504522 time 2016-12-26 11:49:42
...

依據地位信息,我們確定了誤操作sql來自同一個事務,精確地位在257427-504272之間(binlog2sql關於同一個事務會輸入異樣的start position)。再依據地位過濾,運用 -B 選項生成回滾sql,反省回滾sql能否正確。(注:真實場景下,生成的回滾SQL常常會需求進一步挑選。結合grep、編輯器等)

shell> python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -tuser --start-file='mysql-bin.000054' --start-position=257427 --stop-position=504272 -B > /tmp/rollback.sql
rollback.sql 輸入:
INSERT INTO `test`.`user`(`addtime`, `id`, `name`) VALUES ('2016-12-14 23:09:07', 24530, 'tt'); #start 257427 end 504272 time 2016-12-26 11:44:56
INSERT INTO `test`.`user`(`addtime`, `id`, `name`) VALUES ('2016-12-12 00:00:00', 24529, '小李'); #start 257427 end 504272 time 2016-12-26 11:44:56
...
INSERT INTO `test`.`user`(`addtime`, `id`, `name`) VALUES ('2014-11-11 00:04:48', 2, '小錢'); #start 257427 end 265754 time 2016-12-26 11:44:56

 shell> wc -l /tmp/rollback.sql
16128 /tmp/rollback.sql

與業務方確認回滾sql沒問題,執行回滾語句。登錄mysql,確認回滾成功。

 shell> mysql -h127.0.0.1 -P3306 -uadmin -p'admin' < /tmp/rollback.sql

 mysql> select count(*) from user;
+----------+
| count(*) |
+----------+
|  16389 |
+----------+

TIPS

閃回的關鍵是疾速挑選出真正需求回滾的SQL。 先依據庫、表、時間做一次過濾,再依據地位做更精確的過濾。 由於數據不斷在寫入,要確保回滾sql中不包括其他數據。可依據能否是同一事務、誤操作行數、字段值的特征等等來協助判別。 執行回滾sql時如有報錯,需求查實詳細緣由,普通是由於對應的數據已發作變化。由於是嚴厲的行形式,只需有獨一鍵(包括主鍵)存在,就只會報某條數據不存在的錯,不用擔憂會更新不該操作的數據。 假如待回滾的表與其他表有關聯,要與開發闡明回滾和不回滾各自的反作用,再確定方案。 回滾後數據變化,能夠對用戶和線上使用形成困惑(相似幻讀)。

再反復下最重要的兩點:挑選出正確SQL!溝通清楚!

閃回工具

MySQL閃回特性最早由阿裡彭立勳開發,彭在2012年給官方提交了一個patch,並對閃回設計思緒做了闡明(設計思緒很有啟示性,激烈引薦閱讀)。但是由於種種緣由,業內裝置這個patch的團隊至今還是多數,真正使用到線上的更是少之又少。彭之後,又有多位人員針對不同mysql版本不同言語開發了閃回工具,原理用的都是彭的思緒。

我將這些閃回工具按完成方式分紅了三類。

第一類是以patch方式集成到官方工具mysqlbinlog中。以彭提交的patch為代表。

優點

上手本錢低。mysqlbinlog原有的選項都能直接應用,只是多加了一個閃回選項。閃回特性將來有能夠被官方收錄。
支持離線解析。

缺陷

兼容性差、項目活潑度不高。由於binlog格式的變化,假如閃回工具作者不及時對補丁晉級,則閃回工具將無法運用。目前已有多位人員辨別針對mysql5.5,5.6,5.7開發了patch,局部項目代碼地下,但總體上活潑度都不高。 難以添加新功用,實戰效果欠佳。在實戰中,常常會遇到現有patch不滿足需求的狀況,比方要加個表過濾,很復雜的一個需求,代碼改動也不會大,但對大局部DBA來說,改mysql源碼還是很困難的事。 裝置稍顯費事。需求對mysql源碼打補丁再編譯生成。

這些缺陷,能夠都是閃回沒有盛行開來的緣由。

第二類是獨立工具,經過假裝成slave拉取binlog來停止處置。以binlog2sql為代表。

優點

兼容性好。假裝成slave拉binlog這項技術在業界使用的十分普遍,多個開發言語都有這樣的活潑項目,MySQL版本的兼容性由這些項目搞定,閃回工具的兼容問題不再突出。 添加新功用的難度小。更容易被改形成DBA自己喜歡的方式。更合適實戰。 裝置和運用復雜。

缺陷

必需開啟MySQL server。

第三類是復雜腳本。先用mysqlbinlog解析出文本格式的binlog,再依據回滾原理用正則停止婚配並交換。

優點

腳本寫起來方便,往往能疾速搞定某個特定問題。 裝置和運用復雜。 支持離線解析。

缺陷

通用性不好。 牢靠性不好。

就目前的閃回工具而言,線上環境的閃回,筆者建議運用binlog2sql,離線解析運用mysqlbinlog。

關於DDL的flashback

本文所述的flashback僅針對DML語句的疾速回滾。但假如誤操作是DDL的話,是無法應用binlog做疾速回滾的,由於即便在row形式下,binlog關於DDL操作也不會記載每行數據的變化。要完成DDL疾速回滾,必需修正MySQL源碼,使得在執行DDL前先備份老數據。目前有多個mysql定制版本完成了DDL閃回特性,阿裡林曉斌團隊提交了patch給MySQL官方,MariaDB估計在不久後參加包括DDL的flashback特性。DDL閃回的反作用是會添加額定存儲。思索到其使用頻次真實過低,本文不做詳述,有興味的同窗可以自己去理解,重要的幾篇文章我在參考材料中做了援用。

有任何問題,或有mysql閃回相關的優秀工具優秀文章脫漏,煩請告知。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved