背景
由于运维、DBA的误操作或是业务bug,我们在操作中不可避免的会出现误删除数据情况。目前,TiDB只提供了类似oralce的 Flashback Query,详细说明参见TiDB 历史数据回溯。但其查询时间受限与GC且不能生成闪回SQL。延长GC的时间,则存在以下问题:
- 磁盘空间占用较多
- 大量的历史版本会在一定程度上影响性能,尤其是范围查询(如
select count(*) from t
)
对于MySQL DBA来说,有很多基于binlog实现的开源的闪回工具,如binlog2sql、MyFlash。TiDB也提供了类似MySQL的binlog,因此可以基于类似的方法实现TiDB的闪回。
TiDB Binlog
TiDB Binlog 集群主要分为 Pump 和 Drainer 两个组件,以及 binlogctl 工具:
Pump
Pump用于实时记录 TiDB 产生的 Binlog,并将 Binlog 按照事务的提交时间进行排序,再提供给 Drainer 进行消费。
Drainer
Drainer 从各个 Pump 中收集 Binlog 进行归并,再将 Binlog 转化成 SQL 或者指定格式的数据,最终同步到下游。
binlogctl 工具
binlogctl 是一个 TiDB Binlog 配套的运维工具,具有如下功能:
- 获取 TiDB 集群当前的 TSO
- 查看 Pump/Drainer 状态
- 修改 Pump/Drainer 状态
- 暂停/下线 Pump/Drainer
binlog的格式介绍参见TiDB Binlog 源码解析
方案介绍
从上面关于TiDB Binlog的介绍中,我们知道Drainer从各个Pump收集Binlog进行归并,再将Binlog进行转换。 从drainer的配置文件中,可以看到下游服务类型有四种,
-dest-db-type string
Drainer 下游服务类型 (默认为 mysql,支持 tidb、kafka、file)
因此,可以通过新增加一种下游服务类型来实现flashback。
参数介绍
相较drainer,新增了几个参数,同时对之前的dest-db-type做了类型的扩充
-dest-db-type string
target db type: mysql or tidb or file or kafka or flashback; see syncer section in conf/drainer.toml (default "mysql")
-do-dml string
do-dml : insert ,update ,delete ; you can choose more than one ,default all dmls
-end-time string
flashback end in end-time, empty string means never end.
-end-tso int
similar to end-time, but in pd-server tso format
-start-time string
flashback from start-time, empty string means starting from current time
-start-tso int
similar to start-time but in pd-server tso format
实现原理
1、新增一个syncer类
在createDSyncer函数中新增NewFlashBackSyncer,相较其他的syncer函数,增加了限制参数,如start-time、do-dml等,而对相关库表的过滤,依赖与drainer之前实现的过滤方法
2、将tidb的binlog改成闪回用的binlog
这块的改写逻辑类似与MySQL的闪回改写逻辑,详情参见闪回思路
3、新增对tidb binlog生成语句的函数
通过新增的ToOriginalSQL和ToFlashBackSQL,生成原始和闪回的SQL
操作
实际使用和drainer没有太大区别,如:
drainer -pd-urls https://127.0.0.1:2379 -dest-type flashback -start-time "209-12-25 00:00:00" -end-time "2019-12-25 10:00:00"
操作结果会产生三类文件:闪回的binlog文件、原始SQL文件、闪回SQL文件,闪回的binlog文件可以直接使用reparo进行操作。
上面简单讲解了闪回工具的实现,后续这块会作为PR提交给官方,到时欢迎吐槽和拍砖。