MySQL闪回实现

来自技术开发小组内部wiki
跳转至: 导航搜索

前提:binlog_format=row,因为只有row模式会记录更新前后的整行记录。


原理

1.单个语句的闪回

平时的DML无非三种操作,增删改,先说三种操作的日志格式。
一个语句分成两个event (实际上不止,其他可以忽略),一个table_map event 和 一个Rows_log_event。Table_map event是一样的,主要看Rows_log_event。
每个Rows_log_event中包含event_type, 可选值为WRITE_ROWS_EVENT、UPDATE_ROWS_EVENT、DELETE_ROWS_EVENT。从宏名字就能看出用途。
对于insert和delete,event中包含了插入/删除的记录的所有字段的值。
对于update操作,event中依次记录旧行, 新行的值。
因此我们看到,这些信息足够让我们对单个操作实现“逆操作”。
i.对于insert操作,只需要把event_type改成DELETE_ROWS_EVENT;对于delete操作,改成WRITE_ROWS_EVENT。
ii.对于update操作,只需要把event中的旧行和新行值对调即可。

2.binlog的闪回

我们只需要把binlog文件反向执行,每个操作都执行逆操作即可。当然也不是所有的event都反转。Table_map event必须还是在Rows_log_event每个操作之前。
目前的方案是用  mysqlbinlog工具,增加一个flashback参数,输出结果为一个新的binlog文件――姑且叫做flashbacklog,这个flashbacklog顺序执行,
可制定某张表和执行到 哪个pos,来实现数据库的闪回。


安装

tar xvfz mysql-5.5.18.tar.gz
cd mysql-5.5.18
patch -p0 < /work/5.5.18_flashback.diff
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql_flashback
make
make install
生成的mysqlbinlog文件就带有闪回功能,为使用方便,复制一份到mysql的bin目录,并更名为mysqlflashback。
cp mysqlbinlog mysqlflashback


使用

-B参数,指定用于闪回数据。其它参数同mysqlbin。
mysqlflashback -B -vv --start-position=298 --stop-position=553 mysql-bin.000001 > /work/01.sql --查看
mysqlflashback -B -vv --start-position=298 --stop-position=553 mysql-bin.000001 | mysql -S/tmp/mysql55.sock test --执行闪回
position获取一例:
update执行过程 Query--Table_map--Update_rows--COMMIT,如下回滚position为298-553
# at 298
#140430 11:19:04 server id 1  end_log_pos 366   Query   thread_id=3     exec_time=0     error_code=0
.
.
# at 366
# at 412
#140430 11:19:04 server id 1  end_log_pos 412   Table_map: `test`.`tt` mapped to number 39
#140430 11:19:04 server id 1  end_log_pos 526   Update_rows: table id 39 flags: STMT_END_F
.
.
# at 526
#140430 11:19:04 server id 1  end_log_pos 553   Xid = 682
COMMIT/*!*/;


参考

http://dinglin.iteye.com/blog/1539167
http://mysql.taobao.org/index.php/Patch_source_code#Add_flashback_feature_for_mysqlbinlog(工具的源码补丁包下载地址)