人生在世,难免有手滑的时候。没有悄悄咪咪删过表数据的程序员的人生,一定是不完美的。特别是连续加班后,带着昏沉沉的大脑,难免会一个不留神,写下了罪恶的foreach remove语句。满怀信心的一看数据库。啪,快乐没有了!表数据因为不合适的查询条件,进行了全表数据删除的操作!
此时的你一定万分慌张,甚至已经收拾好行李,准备下一秒就提着桶跑路了!
为什么要跑路呢?因为你不知道接下来该如何处理,只能依靠工具猴最原始的自我保护机制,驱使自己前进。
除了跑路,我们还能做些什么呢?!别慌,下面就来讲讲遇到这种情况,我们该如何从容应对。
全文的数据修复基础在于mysql的binlog功能,所以下文会从binlog的原理、使用等几点方面来介绍如何进行数据修复。
binlog是记录所有数据库表结构变更(例如CREATE、ALTER TABLE…)以及表数据修改(INSERT、UPDATE、DELETE…)的二进制日志。
binlog不会记录SELECT和SHOW这类操作,因为这类操作对数据本身并没有修改,但你可以通过查询通用日志来查看MySQL执行过的所有语句。
binlog可以用于记录mysql的数据变更,数据在恢复的时候binlog日志能起到很大的作用。mysql的主从复制就是利用的binlog原理。
因为一切基于binlog日志,所以binlog日志必须处于开启状态下,才会记录开启之后的表结构变更和表数据修改。如果你删数据后发现binlog日志没开且正好又是生产环境,那恭喜你,你基本只能跑路了!
登录mysql后执行以下语句show variables like 'log_%';
从中我们可以看出,binlog并没有处于开启阶段。
my.cnf
路径如果不知道位置,可以执行以下命令/usr/local/mysql/bin/mysql --help --verbose | grep my.cnf
/etc
新建文件my.cnf
并添加如下内容[mysqld]
# log_bin
log-bin = mysql-bin #开启binloglc
binlog-format = ROW #选择row模式
server_id = 1 #配置mysql replication需要定义,不能和canal的slaveId重复
my.cnf
文件追加644权限,sudo chmod 644 my.cnf
此时已经将binlog打开了~~
mysql默认使用mysqlbinlog作为flashback工具,你可以进入以下路径查看是否已经安装
/usr/local/mysql/bin/
可以通过以下命令来查看binlog数据,前提是你的mysql必须已经安装了mysqlbinlog(通常是自带的)
通过执行以下命令,可以查看binlog里已经记录的操作
/usr/local/mysql/bin/mysqlbinlog -vv mysql-bin.004777
end_log_pos 表示binlog中的命令位置
table_map 代表操作的库和对应的表
Delete_rows: table id 129 flags: STMT_END_F 代表记录的具体操作,其中Delete可以是Update或者Write等
当然我们还可以通过mysqlbinlog自带的命令对数据进行定位查询,可以追加以下参数
–start-position=849196 代表起始位置,其中的数值就是上文中的end_log_pos
–stop-position=1526352 代表最终位置,其中的数值就是上文中的end_log_pos
–start-datetime=“2015-06-28 8:45:00”
–start-datetime=“2015-06-28 10:10:00”
此时的命令可以变为:
/usr/local/mysql/bin/mysqlbinlog --start-position=849196 --stop-position=1526352 -vv mysql-bin.004777
通过以上方式你就可以从binlog中找到在某段时间的具体操作了~~
当然,你还可以通过/usr/local/mysql/bin/mysqlbinlog命令获取支持的其他操作!
查找出来的数据你可以通过管道grep的方式对数据进行进一步的筛选~~这里就不做说明了~
通过以上的查询,你可以在binlog中定位出自己需要rollback的数据的位置了。但是光光这样还是不够的,在实际操作中,还有一些鲜为人知的坑,下面针对这些坑进行说明。
binlog的操作回滚命令为:
./mysqlbinlog -B -T goods_sku --start-position=849196 --stop-position=1526754 mysql-bin.004777 | mysql -h 127.0.0.1 -u root -p
-B 代表进行flashback操作
-T 代表具体回滚操作的数据表
–start-position 回滚的开始位置
–end-position 回滚的结束位置
mysql -h 127.0.0.1 -u root -p 将数据回滚的目标数据库
并不是所有的mysqlbinlog都支持回滚操作的,因为mysqlbinlog分为多个版本,部分版本不支持-B命令,所以,这时候我们要通过/usr/local/mysql/bin/mysqlbinlog
来查询mysqlbinlog工具是否满足flashback操作。
只有支持的命令中包含-B
操作指令,才能进行flashback回滚~~~
当然,如果你服务器上面的mysqlbinlog不支持-B
操作命令,那又该怎么处理呢?
本人因为苦搜全网没有找到正确的mysqlbinlog工具,于是乎从同事的机子上将支持-B命令的mysqlbinlog.bin文件对本地的进行了替换,临时解决了上述问题。
不支持在 Docs 外粘贴 block
好了,mysqlbinlog准备好了,接下来就可以开开心心执行命令等待数据恢复了?不,你不可以!在执行过程中可能会遇到以下常见问题:
之所以报这个问题,是因为mysql中缺少check_constraint_checks
这个系统参数!而这个参数,是mariaDB独有的!
我们可以通过以下命令查看是否含有check_constraint_checks
参数
show global variables LIKE "%system%"
很显然,目前的系统中并没有对应的参数。
目前的解决方案是通过docker去下载一个mariaDB,通过将mariaDB作为目标数据库,来规避这个问题。
在回滚的过程中还可能碰到其他奇奇怪怪的问题,比如会报缺少相关主键等问题~
因为回滚操作是从后往前进行逆向执行的,所以有时候遇到write指令的时候会导致报主键不存在的错误,这时候就需要好好分析binlog文件,制定相应回滚策略。
当一切都准备妥当了大家都可以不用跑路了安安心心恢复数据,快快乐乐继续当打工人了!
研究了一下binlog2sql这个工具,是大众点评开源的一款用于解析binlog的工具。
官网地址如下:
https://github.com/danfengcao/binlog2sql
使用方法很简单,就如同官网介绍的一样,执行这两个命令就能安装了。
git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql
pip install -r requirements.txt
但是安装过程中可能会遇到一些问题,比如pip命令不存在。
这时候你可以通过以下几个方式进行排查
python -V
命令查看当前python版本,如果版本过低,建议更新成最新的版本。brew
进行安装的,就涉及到python版本切换的问题。下面介绍如何切换版本。export PATH="/usr/local/Cellar/[email protected]/3.9.4/bin:${PATH}"
alias python="/usr/local/Cellar/[email protected]/3.9.4/bin/python3.9"
alias pip="/usr/local/Cellar/[email protected]/3.9.4/bin/pip3"
source .bash_profile
使环境变量生效python -V
命令查看当前版本是否切换成功通过执行以下命令,可以正向的生成binlog中所记录的sql
python /Users/apple/code/binlog2sql/binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uroot -p root -d tg_common -t goods_sku --start-file=mysql-bin.000004
注意,其中的/Users/apple/code/binlog2sql/binlog2sql/binlog2sql.py
需要根据binlog2sql的git clone
路径进行配置
执行结果如下:
反向sql生成命令和正向的差不多,就是多了一个-B的指令
python /Users/apple/code/binlog2sql/binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uroot -p root -d tg_common -t goods_sku --start-file=mysql-bin.000004 -B
可以发现,执行的正好是上面的逆sql(表结构相关命令不生成逆向sql)
正如官网描述的一样,在实际操作中我们发现,无法执行其他路径的binlog文件。
此外,就算把来自外部的binlog文件移动到当前mysql的binlog文件路径下,依旧会报以下错误
即使使用外部文件将当前myql下的binlog文件进行同名替换,依旧会报以下错误
所以,不建议使用binlog2sql这个工具去解析外部binlog文件