netnr 2022-08-13 15:20:08 👁555 💬0

引言

生产环境,某表末尾添加一个字段,保存造成数据库崩溃,idb 文件损坏,数据库版本号 8.0.29,表数据 5K 多条

起因

2022-08-12 12:20 左右,中午吃饭回来打算更新线上程序,同事操作表添加一列,数据库出问题了

线上站点打开缓慢或打不开,接着排查问题

查看服务状态 systemctl status mysqld 正常

客户端连接数据库打开任意表,极慢或打开失败

查看数据库日志发现有错误信息输出

[InnoDB] InnoDB initialization has started.
[InnoDB] InnoDB initialization has ended.

类似 的错误信息:https://github.com/gitpod-io/gitpod/issues/9314 ,还有锁表关键字 lock TABLES

打开任意表,有些能打开有些不能,问题定位到具体某一张表 A (A 表就是添加字段的表,此前没有反应过来)

只要访问 A 表,或关联访问,查看 DDL 等操作都会造成实例重启,均有日志输出

所以,解释了为什么打开缓慢或打不开,因为线上应用程序在持续查询 A 表,实例在不断重启

解决

首先,停止线上应用程序,开始还原数据库备份文件

我们做了数据库备份任务(12 小一次),最新备份为中午 12 点 8 分

接着修改生产环境表 A 为 A2,重新创建表 A,从还原的数据库恢复表 A

对比系统日志记录,备份数据表 A 为最新,万幸!!!

至此,重启应用,一切正常

接着

此时表 A2 就像一个地雷,一踩就爆,我们有定时任务备份,表 A2 肯定会有影响,计划晚上 6 点删除表 A2

嘿嘿,很简单,结果执行删除表 A2,数据库又崩了

先进行了数据库备份

-- 跳过锁表
mysqldump -u root -p --quick --skip-lock-tables -R db > /tmp/db.sql

-- 排除某表
mysqldump -u root -p --ignore-table=db.A2 -R db > /tmp/db_2.sql

接着开始删除表 A2 计划:

  • 修改现有数据库 db 为 db2,重新创建数据库 db,再把数据恢复到 db,排除表 A2,再删除数据库 db2
  • MySQL 不能直接修改数据库名称,所以通过修改表名 rename table db.table to new_db.table;
  • 没考虑到还有视图、存储过程,又改回来
  • 期间有不少尝试:
  • 拷贝表 A2 的 idb 文件进行恢复,alter table A2 import tablespace,但失败了
  • 重启服务器,重启数据库服务,改一些配置文件等等都没用
  • 问题越来越明确到是 idb 文件损坏造成的,突然想到通过截断把数据清空
  • 执行 truncate table A2,竟然成功了,再接着删除表 A2,也成功了!!!

一切都恢复正常,好像很简单就解决了,而过程却是那么的真实。


链接