Linux 文件系统引起的云盘文件系统异常导致 MySQL 数据页损坏事故恢复复盘
事故的起因是因为当我访问某个数据库的某个表的时候,MySQL 立即出现崩溃并且去查看 MySQL 的错误日志出现类似信息
--09T05::.232564Z [ERROR] InnoDB: Space id and page no stored in the page, read in are [page id: space=, page number=], should be [page id: space=, page number=]
--09T05::.232613Z [ERROR] InnoDB: Database page corruption on disk or a failed file read of page [page id: space=, page number=]. You may have to recover from a backup.
--09T05::.232620Z [Note] InnoDB: Page dump in ascii and hex ( bytes): --09T05::.301493Z [Note] InnoDB: Uncompressed page, stored checksum in field1 , calculated checksums for field1: crc32 /, innodb , none , stored checksum in field2 , calculated checksums for field2: crc32 /, innodb , none , page LSN , low bytes of LSN at page end , page number (if stored to page already) , space id (if created with >= MySQL-4.1. and stored already)
InnoDB: Page may be a freshly allocated page
--09T05::.301532Z [Note] InnoDB: It is also possible that your operating system has corrupted its own file cache and rebooting your computer removes the error. If the corrupt page is an index page. You can also try to fix the corruption by dumping, dropping, and reimporting the corrupt table. You can use CHECK TABLE to scan your table for corruption. Please refer to http://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html for information about forcing recovery.
--09T05::.301558Z [ERROR] [FATAL] InnoDB: Aborting because of a corrupt database page in the system tablespace. Or, there was a failure in tagging the tablespace as corrupt.
-- :: 0x7fe307678700 InnoDB: Assertion failure in thread in file ut0ut.cc line Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (7fe2dc03c240): select * from desktop_document2
Connection ID (thread ID):
Status: NOT_KILLED
可以注意到这里就是 MySQL innodb 的数据发生了损坏。可以看到日志的最下面其实这里就是给出的是可能造成崩溃的 query
这里我们可以看到是要因为对 desktop_document2 进行读取造成的。一旦我们对该表尝试读写或者 check table 都会造成 MySQL 崩溃重启。
这里有两种解决思路:
1. 有备份的话将备份找个地方恢复出来,然后重新生成该表。
2. 如果对应到坏的表 check 了之后发现是可有可无可以重新生成的表,可以直接将该表 drop 掉重建。这样可以省出一些恢复的成本和复杂性。
3. 如果坏的数据不可修复,也没有备份。那么需要避开坏数据用 id 偏移的方式尽量扫描更多的数据出来。
然后这里还有个脚本 可以批量扫描坏表。当遇到第一个坏表的时候检查打印出来的 table_name 并做确认。然后排出掉他再继续扫下面的表。
#!/bin/bash
host_name=127.0.0.1
user_name=
user_pwd=
database=
tables=$(/usr/local/webserver/mysql/bin/mysql -h$host_name -u$user_name -p$user_pwd $database -A -Bse "show tables")
for table_name in $tables
do
echo $table_name
check_result=$(/usr/local/webserver/mysql/bin/mysql -h$host_name -u$user_name -p$user_pwd $database -A -Bse "check table $table_name" | awk '{ print $4 }')
if [ "$check_result" = "OK" ]
then
echo "OK TABLE $table_name"
fi
done
需要注意的是使用该脚本在扫描到坏表的时候同样会触发 MySQL 异常重启。
到目前为止来看似乎情况可控,但是遗憾的是造成这次事故继续扩大的是。当时我发现异常损坏发生在系统盘,然后该盘有天级快照。在和各方确认该数据库影响之后我打算直接使用 aliyun 的天级快照来恢复目前糟糕的情况。然后再重新计算当天的相关数据即可,恢复的周期也比较短。
于是关机开始恢复快照 然而等待我的却是

exoo me????
看上去是引导区损坏了,到这里为止就感觉情况变得非常麻烦了。因为快照恢复之后出现这个问题就意味着之前很长一段时间一直都存在引导区因为文件系统损坏而损坏的情况。也就是说可能之前的快照也都坏了,系统盘无法作为引导启动系统。
后来联系 aliyun 工程师通过 liveCD 重启系统,将之前系统挂载到数据盘开始抢救数据。
这里有个值得反思的地方,当时没有做这个机器的数据库备份是因为想到有快照可以依赖,用快照来当备份使用。但是没有考虑打的是,MySQL 的默认数据目录是 /var/lib ,而这个目录存在于数据库上而并非数据盘上。一旦出现类似的文件系统或者引导区损坏重启之后可能就无法进入系统,最严重的情况可能无法使用快照恢复任何数据。
所以说任何时候即使有快照,都应该对你的数据库进行最少天级备份。
在和 aliyun 确认一些信息之后,我列了一个恢复方案最终使用了方案2恢复了数据。下面贴一个 check list
方案1: 1. data02 上用 data- .8日凌晨3点的快照恢复一块 500g 的数据盘。
2. data02 上配置和 data- 上版本相同的 MySQL(5.7.)。
3. 使用 data- 上 MySQL 的数据目录恢复出当时 MySQL 的情况并且启动 MySQL
4. 使用 innobackupex 将机器上的数据库全量备份出来,同时查看数据完整性情况,使用脚本 check table 检查完整性。
5. 将 data- 机器还原成初始配置,安装同样版本的数据库,并且使用备份恢复数据库数据。 方案2: 1. 直接在 data- 上重置系统。☑️
2. 然后使用镜像挂一个 500g 的盘。☑️
3. 通知 aliyun 工程师使得新挂载的盘变得可读。☑️
4. 安装 MySQL 5.7. 数据库。☑️
5. 将数据库文件找个地方拷贝出来。☑️
6. 将数据文件恢复至 新安装的 5.7. 数据库,并且不保证相关账号密码都和以前一致。☑️
这里要提一下方案2的todo 6,如果全量恢复整个数据库的数据,可以直接将整个数据目录进行覆盖,然后重启数据库就可以简单的直接通过文件恢复数据库。
如果是单纯的要恢复某个表或者某个库,最好还是找机器全量恢复之后,使用 mysqldump 或者 pxb 备份对应的库表进行恢复比较简单。直接通过恢复文件的形式恢复单个表库实在太过于复杂了,感觉没必要。
截止到目前数据库就已经恢复了,剩下的还是要 drop 掉坏掉的表进行重建,或者参照上面的方法进行数据抢救。
其实在之前一个月就发现该机器有一些奇怪的报错日志 类似于
Aborted connection to db: 'test' user: 'root' host: '127.0.0.1' (Got timeout reading communication packets)
后来看了一些资料,这些都是一些网络超时错误,与此次事故无关,可以根据 http://mysql.taobao.org/monthly/2017/05/04/ | https://www.percona.com/blog/2016/05/16/mysql-got-an-error-reading-communication-packet-errors/ 来仔细排查网络问题。
小结:
不管有没有快照或者别的保护措施都应该对数据库进行天级备份,有备无患。
当能恢复接触到数据的时候应该第一时间对数据进行再备份,保证至少当前状态可以保证不再恶化。
要第一时间通知相关小伙伴事故处理的进度,以及通知到受影响的小伙伴获得他们的支持,恢复之后第一时间恢复相关服务。
Reference:
https://zhuanlan.zhihu.com/p/60327406 MySQL通过frm、ibd文件恢复innodb数据
http://www.yunweipai.com/archives/19844.html MySQL 如何利用 ibd 文件恢复数据
http://mysql.taobao.org/monthly/2017/05/04/ MySQL · 答疑解惑 · MySQL 的那些网络超时错误
https://www.percona.com/blog/2016/05/16/mysql-got-an-error-reading-communication-packet-errors/ mysql-got-an-error-reading-communication-packet-errors
https://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html Forcing InnoDB Recovery
Linux 文件系统引起的云盘文件系统异常导致 MySQL 数据页损坏事故恢复复盘的更多相关文章
- Linux—挂载磁盘(云盘)
创建挂载目录 [root@localhost ~]# mkdir -p /www 可以看到/dev/vda1盘挂载/ /dev都是位于根路径下,都属于系统盘.根路径 / 都是位于系统盘.而/root, ...
- 捉虫日记 | MySQL 5.7.20 try_acquire_lock_impl 异常导致mysql crash
背景 近期线上MySQL 5.7.20集群不定期(多则三周,短则一两天)出现主库mysql crash.触发主从切换问题,堆栈信息如下: 从堆栈信息可以明显看出,在调用 try_acquire_loc ...
- 【Linux】扩展阿里云数据盘分区和文件系统
扩容云盘只是扩大存储容量,不会扩容文件系统 一.准备工作 在扩展数据盘扩展分区和文件系统前,请提前完成以下工作. 创建快照以备份数据,防止操作失误导致数据丢失. 通过ECS控制台或者API扩容云盘容量 ...
- .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”
FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...
- linux下转换U盘文件系统
打算在windows 7 下复制一个12G 的文件至U盘,无奈U盘为FAT32格式,最大支持移动4G 的文件,只能将U盘文件系统格式化为NTFS.windows 7系统出现问题,转化中总是出现错误.故 ...
- Linux下的磁盘分割和文件系统
一.各硬件装置在Linux下的文件名 1.IDE硬盘机 在Linux内的文件名: /dev/hd[a-d] (a-d 刚好是四个这个是有原因的具体如下) 解释:以 IDE 接口来说,由于一个 IDE ...
- 如何在 Linux 终端下创建新的文件系统/分区
在 Linux 中创建分区或新的文件系统通常意味着一件事:安装 Gnome Parted 分区编辑器(GParted).对于大多数 Linux 用户而言,这是唯一的办法.不过,你是否考虑过在终端创建这 ...
- 【linux之设备,分区,文件系统】
一.设备 IDE磁盘的设备文件采用/dev/hdx来命名,分区则采用/dev/hdxy来命名,其中x表示磁盘(a是第一块磁盘,b是第二块磁盘,以此类推), y代表分区的号码(由1开始,..3以此类推) ...
- linux.1:创建分区和文件系统
概述 使用 fdisk.gdisk 和 parted 创建和修改 MBR 和 GPT 分区在本教程中,学习磁盘分区和 Linux 文件系统相关内容,包括学习如何: 使用 mkfs 命令设置 ext2. ...
随机推荐
- Windows 系统上用 .NET/C# 查找所有窗口,并获得窗口的标题、位置、尺寸、最小化、可见性等各种状态
原文:Windows 系统上用 .NET/C# 查找所有窗口,并获得窗口的标题.位置.尺寸.最小化.可见性等各种状态 在 Windows 应用开发中,如果需要操作其他的窗口,那么可以使用 EnumWi ...
- WCF与Web API在应用上的选择
在最近发布的Visual Studio 2012及.NET 4.5中, 微软正式推出新的网络服务框架ASP.NET Web API.作为ASP.NET MVC 4的一部分,ASP.NET Web ...
- StatusStrip控件的使用(转:http://blog.sina.com.cn/s/blog_4f18c3ec0100fguf.html)
c# winForm 将窗体状态栏StatusStrip 分成左中右三部分 右边显示当前时间 实现效果: 通过StatusStrip显示窗体状态栏 同时将状态栏分成三部分 居左边显示相关文字信息 中间 ...
- TFTP(Trivial File Transfer Protocol,简单文件传输协议)
TFTP(Trivial File Transfer Protocol,简单文件传输协议),是 TCP/IP 协议族中用来在客户机和服务器之间进行简单文件传输的协议,开销很小.这时候有人可能会纳闷,既 ...
- 【OO学习】OO第四单元作业总结及OO课程总结
[OO学习]OO第四单元作业总结及OO课程总结 第四单元作业架构设计 第十三次作业 第十四次作业 总结 这两次作业架构思路上是一样的. 通过将需要使用的UmlElement,封装成Element的子类 ...
- <P>标签是什么?怎么用!
<P>标签它是一个段落标签,它和<br>标签不一样.会自行起一行段落,并且可以作为一个盒子来使用.可以单独定义它. 比如下图: <p>这个就是一个段落</p& ...
- vue入门模板——只需一个html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- SQL SERVER-AlwaysonResolving
虽然2台都是同步提交,自动failover模式 在辅助副本的AG中先删掉一个可用DB,然后关闭主副本,之后辅助副本变为下图.不能自动failover. 重新开启主副本后,主副本显示一切正常 但是辅助副 ...
- 解决通过vue-router打开tab页,下次进入还是上次history缓存的界面状态的问题
一.问题描述: 1. 跳转模式:界面A-->界面B(界面A中通过 this.$router.push({name:'组件B名称', params: {参数}}) 通过打开新tab页的方式打开界面 ...
- redis哨兵配置 总结
本文内容涵盖 windows下单机部署redis多实例(docker.linux下的配置也可参考本文) redis主从配置 redis哨兵配置 以spring boot redis demo下一个存a ...