从删库到跑路or恢复,记一次MySQL数据库文件损坏恢复经历

1、 前言

2018年5月28日,北京晴有轻度沙尘暴。 坐上公交车走在上班的路上,想起老罗常常提及的一句话:想成盛田昭夫时代的索尼,想成乔布斯时代的苹果,因而继续研读着 《日本制造:盛田昭夫的日式经营学》php

到了人大西门在西区食堂吃了个早餐,穿过人民大学很快就来到了公司。坐在工位上打开电脑登上QQ,不一会运营的CC的头像就开始闪动,“mooc平台登陆不了”,“你看看”。又一会领导的头像开始闪动,“xxx说慕课平台不能登陆了”。 额… 这事都惊动领导了?mysql

2、 排查问题

打开chrome浏览器开始预览,等了很久代理服务器才反馈linux

Time out!nginx

使用 SecureCRT 链接了一下服务器,首先从新启动了一下Nginx代理服务器sql

service nignx stop // 关闭Nginx服务chrome

service nginx start // 开启Nginx服务数据库

去前台刷新了几下没有恢复。 那就在重启一下php吧,因而就centos

service php-fpm stop // 关闭PHP服务浏览器

service php-fpm start // 开启PHP服务安全

又去前台试了试仍是没有恢复。(有人会问为何不直接用 service xxx restart 来重启各服务呢? 我也不知道为何,我的爱好吧!)那只有一种可能数据库出问题了。

打开 Navicat 链接了一下数据库,发现能够正常链接并且能够看到全部的表,随便打开了一张表能看到里面的数据,可是弹出了一个错误的提示。

Got error 28 from storage engine

大概是这个错误提示,当时也没在乎,心想反正提示错误了那就重启一下物理服务器吧,这里是物理服务器!!!随后执行了这个命令(为何不直接重启MySQL服务呢? 过后想了想我也不知道为何。 并且若是当时注意看看这个错误,是由于磁盘空间问题引发的,也许后面就不会有那么多惊心动魄了!)

reboot // 重启物理服务器

执行完之后全部的服务都正常关闭了,只有Mysql数据库服务

Shutdown MySQL ……………………………………………….

引号已经5排了,实在是等不下去了。 断电!!!(MySQL没有安全关闭,直接断电会出问题的!!!)。

3、 恢复进程

等了一会,物理服务器启动起来了。一切的应用服务都正常启动了,只看到在启动MySQL数据库的时候出现了

The server quit without updating pid file (/var/lib/mysql/localhost.localdomain.pid)

等到所有服务加载完成之后手动又进行了一次MySQL数据库启动

service mysql start

依然报前面那样的错误,此时内心开始紧张了起来。 Google了一下这个错误,网上提供了几种解决的方案:

一、 Mysql权限问题

chown -R mysql:mysql /var/lib/mysql/*

chmod -R 660 /var/lib/mysql/*

二、 Mysql 服务已开启

ps -ef|grep mysqld // 查看是否有mysqld进程

kill -9 进程号 // 强制杀死进程

三、 残余数据影响了Mysql服务的启动

删除数据库目录(个人数据库目录为rpm安装默认目录:/var/lib/mysql)下的 mysql-bin.index 文件

四、 Mysql配置文件(默认为:/etc/my.cnf)

配置文件里面没有配置数据库目录,这个问题通常在刚安装MySQL时候会出现

五、 skip-federated字段问题

MySQL配置文件注释掉skip-federated字段

六、 selinux的问题

centos6.8以上默认会开启selinux服务,增强版军用级防火墙。为了查问题能够直接关掉

/usr/sbin/setenforce 0

以上解决方案所有都已经使用过了,都没有解决问题,依然开启服务会报错。 此时的心开始凉了。

回头看了看往期的备份,xxxx_20171208.sql。 都快2018年6月份了,个人上次备份居然是17年12月份的,半年了!都半年没备份过了! (我视乎隐约的感受前段时间是有备份的,备份的服务器硬盘好像被我清理了)。

进入到数据库目录下,看到了除了上述说的 mysql-bin.index 文件之外还有其余的几个文件:mysql-bin.~rec~ 、 ib_logfile一、 ib_logfile0、 ibdata1 想了想是否是这几个也是一些残余文件,所有删了试试。 尝试把这几个文件转移到了其余的目录(使用的mv命令)模拟删除效果,同时还至关于备份。

service mysql start

居然MySQL数据库服务正常启动了! 内心的喜悦涌了上来,赶忙使用Navicat链接一下看看,可以正常链接,看到了数据库。 打开数据库之后全部的表都没有了! 此时心又酸了起来。 一转眼11:30了,时间过的可真快啊,同事叫着一块儿吃饭,此时的我已经全无吃饭的心情了。

恢复表结构

把刚才移走的几个文件又恢复到了原目录里,既然恢复MySQL进程如今没什么但愿了,那就想办法恢复数据吧。 进入到数据库目录(/var/lib/mysql)下找到了个人数据库名字以目录的形式存放。 进去该目录之后发现里面都是以扩展名为:xxxx表.frm文件,这些不都是个人数据库表吗? 里面是否是就存放了全部的数据? 是否是直接拿这些文件就能够恢复数据呢?Google了一下,果真有这方面的文章,大体说: “frm能够恢复表结构,同时InnoDB数据库引擎和MyISAM数据库引擎恢复的方式不同”。

一、 InnoDB数据库引擎

  1. 在一个正常的MySQL数据库服务器(new_server)下创建数据库(new_db),该数据库的名称和异常服务器(old_server)数据库(old_db)保持一致。
  2. 在new_db数据库中创建一张表与old_db的表名称(t_user)一致。
  3. 将new_server服务器的MySQL数据库服务关闭。
  4. 从old_server服务器下old_db的数据库目录下复制t_user.frm文件到new_server服务器下new_db的数据库目录下替换t_user.frm文件。
  5. 开启new_server服务器的MySQL数据库服务。
  6. 使用链接工具链接new_server就能够看到new_db下的表及表结构。

二、 MyISAM数据库引擎

其余和InnoDB数据库引擎操做基本一致,只是在new_server服务器下new_db的数据库目录下建立两个空的文件:t_user.MYD 和 t_user.MYI。

我使用的数据库为InnoDB引擎,无奈的我以上两种方法都使用了,没有恢复任何表结构更没有数据,也许多是我操做有问题吧。 此时看到了目录下有一个文件: ibdata1 Google了一下,能够和xxx.frm配合使用,又一次将new_server服务器的MySQL数据库服务关闭。 直接把old_server服务器下old_db的数据库目录下复制ibdata1文件到new_server服务器下new_db的数据库目录下替换ibdata1文件。

service mysql start

新的服务器也出现了这样的错误,致使错误的很大缘由多是ibdata1文件损坏引发的。

今天北京的天气已经达到了35摄氏度,但此时个人心已经凉了一半了,虽然没有按时备份数据及服务器异常崩溃形成数据丢失比直接删库的责任小了点,可是也办法向公司交代,真的须要开始准备 “离职申请” 了吗?

binlog日志

打开微信

:大家公司用的是什么数据库,是MySQL吗

好友LZ:是的

:公司的MySQL坏了,启动不了了; 数据没有备份; 有什么好办法把数据拿回来吗

好友LZ:大家以前数据的binlog还有吗;经过这个应该能够恢复

:都有

好友LZ:我也没弄过数据恢复,都是DBA搞,感受应该能够的;你先查查看网上有没有解决方案,我这会在上线。

:嗯

原本想说:“你能不能问问好友LZ大家DBA遇到过这种状况吗,帮忙给个方案”;最后仍是没有好意思开出口。 不过binlog这个名字让我忽然想起了数据库目录(/var/lib/mysql)下面几个较大的文件。

这十几个文件就是binlog日志文件,每台服务器上面的个数应该不同,这个文件只有每次重启MySQL服务或者刷新日志(MySQL命令:show master logs)的时候才会新增一个。看了一下我最近的几个文件,2018年1月1六、 2018年3月1八、 2018年4月1八、 2018年5月28这几个时间点产生了新的文件,说明MySQL服务器这几个日期都进行过关闭又开启的操做。

binlog使用

binlog文件简介(网上摘抄)

MySQL的二进制日志能够说是MySQL最重要的日志了,它记录了全部的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二进制日志是事务安全型的。

binlog做用(网上摘抄)

MySQL Replication在Master端开启binlog,Mster把它的二进制日志传递给slaves来达到master-slave数据一致的目的。

数据恢复,经过使用mysqlbinlog工具来使恢复数据。

使用binlog恢复数据以前须要肯定MySQL是否开启binlog日志

show variables like 'log_%';

状态 OFF 为未开启,状态 ON 表示已开启

能够经过MySQL配置文件(默认路径:/etc/my.cnf)开启或关闭binlog日志

vi /etc/my.cnf

使用加上#能够关闭,去掉开启。 修改后须要重启MySQL服务(service mysql restart)才能够生效。

恢复数据(binlog日志方式)

初试mysqlbinlog工具

看到上面的那么多mysql-bin文件,很显然使用centos6.5下rpm方式安装的MySQL默认是打开binlog日志的。 这时咱们就须要用到MySQL的 mysqlbinlog 工具,想使用它首先须要确保已经安装MySQL服务,而后咱们须要找到它的位置

find / -name mysql

2 表示为MySQL可执行文件的目录

3 表示为MySQL的数据库目录

那咱们先简单的使用一下

cd /var/lib/mysql

mysqlbinlog mysql-bin.000001 > mysql-bin.000001.sql

很显然我在使用mysqlbinlog的时候是,直接执行的mysqlbinlog命令,前面并无增长任何路径。 由于默认centos系统会将/usr/bin这个目录配置到环境标量中,若咱们使用的是rpm方式安装的MySQL,默认是安装到/usr/bin目录下的。 能够直接在任何路径下使用/usr/bin目录里的文件。 执行完上面的语句后会发如今当前目录生成一个mysql-bin.000001.sql的文件, 打开文件能够看到不少sql语句。

对于我当前的状况来看并不须要把全部的binlog都处理一遍,上面提到我上次的备份是在2017年12月8日的时候(xxxx_20171208.sql)所以我只须要从 mysql-bin.000009 这个binlog文件开始就能够了。

首先我在另一台服务器上面从新搭建了一个MySQL服务,把mysql-bin.000009之后的几个binlog都拷贝到了这台新的服务器上面去。(服务器出现任何问题,建议不要对该服务器作任何操做,换一台新的电脑或服务来处理,为了保护数据的完整性!)

使用备份文件恢复数据

在新的MySQL上面建了一个和之前同样名称的数据库

mysql -u数据库用户名 -p数据库密码 数据库名称 --default-character-set=utf8 < xxxx_20171208.sql

例:mysql -uroot -proot xxxx --default-character-set=utf8 < xxxx_20171208.sql

使用binlog恢复数据

这时数据库有了,数据表及表结构也有了,那就开始恢复数据吧。

mysqlbinlog mysql-bin.000009 | mysql -uroot -proot

回车立刻就出错了,遇到了两种错误,一种是PRIMARY的错误,一种是找不到记录的错误。 mysqlbinlog在执行mysql-bin.000009文件里的插入语句时出错了。 看了一下mysql-bin.000009文件的建立时间是2017年11月12日,个人备份文件是2017年12月8日,他们两个时间差了二十几天,执行上面恢复语句确定会出现重复插入的问题,数据库里的某些表是由PRIMARY KEY的约束的,因此会致使PRIMARY错误。 这时咱们须要用到mysqlbinlog的参数: start-datetimeend-datetime,顾名思义一个是开始时间一个是结束时间。

mysqlbinlog --start-datetime="2017-12-08 10:00:00" mysql-bin.000009 | mysql -uroot -proot

看了一下我备份的xxxx_20171208.sql大体是2017年12月8日的10左右,没有添加 end-datetime 参数的话默认为该binglog文件下的最后一个时间点。 执行了之后报了一个找不到记录的异常。 应该是执行删除或更新语句的时候没有找到某条记录,时间仍是不对。 因而我就查看了数据库的日志表,最后的时间是2017年12月8日9点32分41秒,有执行了一次

mysqlbinlog --start-datetime="2017-12-08 09:32:41" mysql-bin.000009 | mysql -uroot -proot

依然报错,那怎么办呢,难道这个方法不行?

mysqlbinlog mysql-bin.000009 > mysql-bin.000009.sql

此时打开mysql-bin.000009.sql里面拥有大量的sql语句,发现好多条sql语句在这个时间点下。 看来使用参数来控制行不通。 还好mysqlbinlog工具给咱们提供了另外两个参数start-positionend-position

修改了一下命令

mysqlbinlog --start-position="123456" mysql-bin.000009 | mysql -uroot -proot

果真一切都正常了,执行这个命令须要好久,它要把你这段时间全部的增长、删除、更新都执行一遍。 这里可能还会遇到一个问题,个人这个MySQL服务器里面这有一个数据库,MySQL的binlog文件记录的是全部数据库的增长、删除、更新记录,那怎样只针对某个数据库来操做呢? 这时咱们须要用到mysqlbinlog的database参数

mysqlbinlog --database=xxxx --start-position="123456" mysql-bin.000009 | mysql -uroot -proot

半年的数据,就这么一个一个的binlog文件进行处理的,从晚上6点到夜里的12点完成全部文件的恢复,数据量不是很大,服务器的性能也不是过高,中间出了点问题,不过都是服务器中断的问题。 最后把全部的数据所有恢复了回来,这心惊肉跳的一天!

这是工做7年来出的最大一次事故,去年给本身定的一个目标今年写12篇有质量的文章反馈给互联网,都快过半年了一篇尚未写,没想到第一篇居然是以这种方式书写的。 不知道这篇算不算是有质量,但愿能帮到更多的人。

总结

遇到问题不要盲目,保持清醒的头脑,找清问题,整理好思路才能更有效的解决问题。 对于数据平时不要怕麻烦,注意备份

备注

个人服务器及各软件的版本

  • 操做系统:** centos6.5
  • MySQL:** 5.5.49
  • 安装MySQL方式:** rpm
相关文章
相关标签/搜索