1、事件描述
机器RAID卡故障,待更换RAID卡后,重启数据库,数据库重启失败,错误日志报错如下:
2、分析故障原因
预备基础知识:A、redo log日志的工作原理。B、undo log日志的工作原理。(详细的工作原理请自行google了解。《Mysql运维内参》这本书讲得很清楚可以买来看看》)
简述工作原理:
redo log日志的作用主要是保证数据的持久性(宕机或者数据库crash后能从最近的检查点开始重做redo日志,将数据恢复),undo log主要是为了保证事务的原子性(一个事务可以包含多个部分,要吗整个事务都成功,要不就都不成功。不能只做一半)。 数据库在crash之后,重启时首先做的是redo log日志、redo之后数据库中的数据就是一致的了,在这个基础上做undo log日志(回滚未提交的事务,将数据恢复到“问题”’事务之前的状态。保证了事务的原子性)。问题到这里就有点眉目了,undo log 操作是在redo log 操作之后的。《Mysql运维内参》可参照
分析:
(如果按照正常情况、页面的LSN的值怎么可能大于redo log的LSN值?)但根据数据库的错误日志显示,数据页的LSN数值确实大于redo log日志的数值(机器不会说谎)。那么造成这样结果的原因就在于“undo log” 日志回滚操作被意外(或者人为)终止了,使数据并未成功回滚到“问题”事务之前的状态,这就造成数据页面的LSN大于了redo log日志的LSN值。 这样就造成了indodb引擎在启动的最后一步(数据回滚)出现了问题,innodb引擎检测到数据一致性和完整性都已经丧失,因此决定退出不提供服务。《Mysql运维内参》可参照
分析追加:
如果还是没有真正的理解这个报错的产生原因,或者想理解的更深一点。就需要去深入了解redo log原理、undo log原理、 redo undo的时机、innodb引擎启动过程、重点照顾下undo log的详细过程。上边的报错就是undo log 的时候,回滚中断造成的。(因为只有这个时候,事务还没提交,redo log 日志还没记录。但undo log 和回滚段确是记录的。因为undo log和回滚段要提供回退的功能和MVCC功能吗)《Mysql运维内参》可参照
3、造成上述报错条件及预防措施
***只要中断undo log的回滚操作就可实现。比如我这次是遇见了RAID卡故障、造成数据库在系统故障的情况下,回滚失败,造成了数据一致性、完整性丢失。
***当然如果有人为的执行大事务,因等待时间太长而终止。然后又kill -9 掉数据库也是会造成数据回滚失败的。因此一定不要随便kill -9 掉数据库。(不等1分钟、你就要花费百倍的时间恢复数据库。谁催也不管)。
***还有当用xtrabackup物理备份数据库做数据库迁移的时候也会遇见此类的报错,但此时并不是数据 corrupt(数据没问题)。只是由于自mysql5.6之后如果配置文件中对innodb重做日志的配置和innodbbkup工具备份出的的日志大小不一样,会将备份文件中的redo log 日志删除重建(就是ib_logfile*文件)。因此在用innobackupex工具备份迁移数据库的时候,注意将配置文件与源服务器品配置文件对一下(最好一样、不能完全一样的保证这些参数一样也行。这就需要你了解配置文件选项中的每一个含义)
4、如何恢复(数据量不大的同学还好受点,数据量很大的同学就需要多花时间恢复了)
***正确的方法:这对于做好备份的同学比较好、如果备份的数据量不是很大就更好解决了。
非常遗憾的说一句,你倒霉了(数据一致性、完整性已经丢失了,修数据页不太现实)。赶快拿出数据库的备份(如果你有的话、尽量使用备份恢复。这就体现了备份的越好恢复得越好)。恢复我就不说了,如果恢复不熟练的话,说明你平时没有进行数据库恢复演练。没做到位
****弥补的方法:没做备份的同学或者备份做的不好的同学。按照下述方法,可以恢复数据库。但一般会有部分数据不一致(没有回滚吗)
英语好的同学——》https://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html
英语不好的同学:
A、配置选项如下,数值从1-6逐渐递增(最好别超过3、包括3。2能启动不用3,如果实在不行就增加该值。因为值为3的时候数据是真的没有回滚,完整性、一执行会有问题、对于数据一致性要求很高的场景是不行的。不在乎或者能接受部分数据页完整性一致性丢失的那就用吧)之后重启数据库(能起来最好、起不来或者起来后数据库不稳定的想办法使其尽量稳定,可以试着重命名ib_logfile*文件,最好被删除任何文件)。
B、mysqldump备份出所有数据,不要用innobackupex备份,因为是物理备份吗,恢复的时候还是会回滚的。
C、重做数据库恢复(源数据目录能保留就保留)。
配置如下:
[mysqld]
innodb_force_recovery = 1
innodb_force_recovery
在紧急情况下, 仅设置为大于0的值,以便可以启动InnoDB
和转储表。在这样做之前,请确保您具有数据库的备份副本,以防需要重新创建数据库。4或更高的值可能会永久损坏数据文件。innodb_force_recovery
在成功测试数据库的单独物理副本上的设置后,只能在生产服务器实例上使用 4或更大的设置。强制InnoDB
恢复时,您应该始终从头开始, innodb_force_recovery=1
只有按需增量增加值。
innodb_force_recovery
默认为0(正常启动而不强制恢复)。允许的非零值为 innodb_force_recovery
1到6.较大的值包括较小值的功能。例如,值3包括值1和2的所有功能。
如果您可以将innodb_force_recovery
值转换为3或更小的值转储 ,那么您相对来说,只有损坏的单个页面上的某些数据丢失是比较安全。4或更高的值被认为是危险的,因为数据文件可能永久损坏。值为6被认为是剧烈(不负责任)的,因为数据库页面处于不被重视的状态,这反过来可能在B树 和其他数据库结构中引入更多的损坏。
作为安全措施,InnoDB
防止 INSERT
, UPDATE
或 DELETE
操作时, innodb_force_recovery
值被设置成大于0时。
从MySQL 5.6.15,innodb_force_recovery
设置成4 及以上的值的时候。InnoDB
只提供只读服务。
数值说明:
-
1
(SRV_FORCE_IGNORE_CORRUPT
)让服务器运行,即使它检测到损坏的 页面。尝试 跳过损坏的索引记录和页面,这有助于倾倒表。
-
2
(SRV_FORCE_NO_BACKGROUND
) -
3
(SRV_FORCE_NO_TRX_UNDO
) -
4
(SRV_FORCE_NO_IBUF_MERGE
)阻止插入缓冲区合并操作。如果他们会造成事故,不做。不计算表 统计。此值可能会永久损坏数据文件。使用此值后,准备删除并重新创建所有辅助索引。从MySQL 5.6.15开始,设置
InnoDB
为只读。 -
5
(SRV_FORCE_NO_UNDO_LOG_SCAN
)启动数据库时 不查看undo日志:
InnoDB
将即使不完整的事务视为已提交。此值可能会永久损坏数据文件。从MySQL 5.6.15开始,设置InnoDB
为只读。 -
6
(SRV_FORCE_NO_LOG_REDO
)无法 与恢复相关联的重做日志向前滚动。此值可能会永久损坏数据文件。使数据库页面处于过时状态,从而可能会在B树和其他数据库结构中引入更多的损坏。从MySQL 5.6.15开始,设置
InnoDB
为只读。
参考网址:
https://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html
http://blog.itpub.net/22664653/viewspace-762668/
http://imysql.com/2015/04/23/mysql-faq-mysqld-start-fail-case1.shtml
http://blog.cuicc.com/blog/2015/10/12/mysql-can-not-startup-after-loss-power/