一位小伙伴不小心误删了生产环境上mysql数据下/data/mysql/ibdata1和ib_logfile0、ib_logfile1文件,并且mysql服务停止了,造成mysql重启不了,吓得小伙伴以为要“被删库跑路”了,于是赶紧帮忙”救火”。像这种误删数据或者删库的情况,不能慌,更不能病急乱投医,冷静分析下具体原因,对症下药。
恢复数据方法1-binlog日志
处理生产环境下数据库问题,最首要问题就是要保证数据不能丢,在数据完整的前提下在保证应用的服务正常。所以,第一首要问题是恢复并备份数据,不幸的是数据库没有做数据备份,但万幸的是有binlog日志文件,这样可以通过它进行数据恢复。
我把binlog文件拷贝到本地,在本地导入到新的mysql库中。binlog日志文件里存的是二进制内容,所以需要用mysqlbinlog命令转化成mysql能够执行的语句,如下:
#通过binlog日志文件恢复数据
mysqlbinlog --no-defaults --database=testdatabase /home/devops/nankai/binlog.000001 | /usr/bin/mysql -uroot -proot -v testdatabase
#通过start-position到stop-position
mysqlbinlog --no-defaults --start-position=40107 --stop-position=40489 --database=weijianwei /home/devops/binlog.000001 | /usr/bin/mysql -uroot -p123456 -v
#在执行上面脚本的时候总是报各种错误,于是我想着把转化后的内容存到一个TXT文件中,这样就能看懂
mysqlbinlog --no-defaults --database=testdatabase /home/devops/binlog.000002 >> /home/devops/testdblogs-bak.txt
#对于一些报错的语句或者不重要语句可以在TXT文件中删除了,然后再执行
cat /home/devops/nankaidblogs20210617.txt | /usr/bin/mysql -uroot -proot -v
在执行“cat /home/devops/nankaidblogs20210617.txt | /usr/bin/mysql -uroot -proot -v”时还出现报错:
ERROR 2006 (HY000) at line 1: MySQL server has gone away
这是由于脚本内容太大,造成连接超时了,需要在my.cnf配置中添加如下配置就能解决了:
max_allowed_packet = 64M
wait_timeout = 6000
恢复数据方法2-innodb_force_recovery参数
这个方法的前提是你的数据文件(.ibd数据文件)都还在,具体思路是:
1、从别的服务器数据库中拷贝一份ibdata1、ib_logfile0、ib_logfile1文件到原路径下
2、使用innodb_force_recovery参数,使mysqld跳过恢复步骤,启动mysqld,将数据导出然后重建数据库。
在/etc/my.cnf文件中添加以下配置:
innodb_force_recovery = 6
添加该配置后重启:
# 启动
service mysqld start
service mysqld restart
service mysqld status
重启数据库成功,然后也能顺利登录,登录进行之后发现数据都还在,并且都还能正常访问,于是赶紧进行数据备份:
#登录
mysql -uroot -p
#进行数据备份
./mysqldump -hlocalhost -uroot -p --all-databases > /data/mysql/alldata-bak20210617.db
./mysqldump -hlocalhost -uroot -p mydatabase> /data/mysql/mydatabase-bak.db
虽然数据库重启成功了,但是现在高兴还太早。因为此时的数据库只能进行查询操作,不能执行增删改的操作。查询了很多网上资料说把innodb_force_recovery 改回 0,然后删除mysql库中所有数据,且把/data/mysql/下ibdata1、ib_logfile文件也删除了,然后重启mysql就会重新生成新的ibdata1、ib_logfile文件,然后再重新导入备份数据即可,但是我按照此方式没有操作成功,于是有了我下面恢复数据库的方式。
注:innodb_force_recovery 可以设置为1-6,大的数字包含前面所有数字的影响
1、(SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页。2、(SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行full purge操作,会导致crash。3、(SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。4、(SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。5、(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。6、(SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。
恢复数据库
数据恢复了,心里就有底气了,后面可以放心大胆的折腾数据库了,大不了卸载了重装,当然尽量省时省事的原则来处理。
在尝试了广大网友的各种方法之后还是不能正常恢复启动mysql,但又不想重新装数据库,所以我想着干脆把mysql数据的数据全部初始化了,然后重新登录新建数据库表导入备份数据。步骤如下:
1、删除mysql下所有数据文件(警告:删除之前先备份一下原来的文件以防万一,等成功之后可以删除了),我的是在/data/mysql/路径下,具体可以查询/etc/my.cnf文件配置。
2、数据库初始化,在数据库安装路径下执行:
./mysqld --initialize-insecure
然后新生成了一个mysql数据文件,这时候数据库就跟刚安装好是一样的状态,需要修改root用户的密码。
先在my.cnf中添加免密码登录配置:skip-grant-tables,然后重启服务,就可以直接mysql回车免密登录了,然后修改密码。详细执行脚本如下:
FLUSH privileges;
update user set authentication_string='' where user = 'root';
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
FLUSH privileges;
一开始我先是上面方式设置密码,但发现MySQL 连接出现 Authentication plugin ‘caching_sha2_password’ cannot be loaded报错,出现这个原因是mysql8 之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是caching_sha2_password, 解决问题方法有两种,一种是升级驱动,一种是把mysql用户登录密码加密规则还原成mysql_native_password,为了减少麻烦我是选择了第二种,执行脚本如下:
FLUSH privileges;
update user set authentication_string='' where user = 'root';
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';
FLUSH privileges;
这样之后就能用root用户正常登录mysql了,登录之后就新建数据库,然后倒入之前备份的数据,一切就OK了。
CREATE DATABASE IF NOT EXISTS mydatabase DEFAULT CHARACTER SET utf8;
use mydatabase;
source /data/mydatabase-bak.db;
还好数据库恢复了,数据也保住了,但给我们一些警告:
1、做好定期数据备份
2、rm命令一定要慎用(尤其使用的root用户权限),使用之前最好先备份
3、谨记1/2条