当前位置:首页 > 问答 > 正文

MySQL升级时遇到表空间获取失败报错,远程帮忙修复方案分享

根据多次线上数据库维护实战记录及DBA社区问题排查案例汇总)

那次真是挺紧急的,一个核心业务的MySQL数据库计划从5.7版本升级到8.0,前期测试环境都挺顺利的,但就在正式环境升级后,应用突然报出一大堆错误,日志里密密麻麻地刷着类似“Cannot get table metadata”或者“Tablespace for table dbname.tablename is missing”这样的错误信息,简单说,就是MySQL服务器找不到一些表的“家”了,也就是表空间文件出了问题,当时应用已经部分不可用,情况非常棘手。

由于是远程支持,我们没法直接登录到服务器上,只能指导现场同事一步步操作,我们让他立刻停止了所有尝试连接数据库的应用,避免产生更多脏数据或加剧问题,我们让他检查了MySQL的错误日志文件,这是定位问题的第一步,也是最关键的一步,错误日志里除了刚才提到的表空间丢失的报错,还明确指出了是哪些具体的数据库和表出了问题,这让我们松了一口气,因为问题看起来是局部的,不是整个数据库都崩溃了。 来源:基于MySQL官方文档关于数据恢复和文件系统权限的章节,以及处理类似故障的实操经验)

MySQL升级时遇到表空间获取失败报错,远程帮忙修复方案分享

我们怀疑是不是升级过程中文件权限发生了变化,MySQL 8.0对安全要求更高,有时候升级脚本或者操作系统层面的变动,可能导致MySQL服务运行用户(通常是mysql)对数据目录(datadir)下的文件失去了读写权限,我们让同事在服务器上执行了ls -l命令,查看报错的那些表对应的.ibd文件(InnoDB表的表空间文件)的权限,果然,发现有几个文件的属主或者权限不对,不是mysql:mysql,我们指导他使用chownchmod命令,将这些文件的所有权和权限修正过来,修正之后,重启MySQL服务,但遗憾的是,问题依旧,这说明权限问题只是其中之一,或者不是主要原因。 来源:参考了Percona博客中关于InnoDB数据字典不一致和mysql tablespace特性恢复的案例)

排除了权限问题,我们开始考虑更棘手的情况:数据字典不一致,MySQL内部有一个数据字典,记录着所有表的结构、位置等信息,在升级过程中,如果因为意外(比如升级中断又继续、磁盘空间不足等),可能导致数据字典里记录的表信息(比如表空间ID)与实际磁盘上的表空间文件不匹配,这时候,MySQL就会“认不出”这个表了。

我们采取的方案是尝试“强制”让MySQL重新认识这个表,这里用到了一个有点“黑科技”但很有效的方法——利用MySQL的“可传输表空间”特性,具体步骤稍微复杂一些,我们远程指导现场同事一步步操作:

MySQL升级时遇到表空间获取失败报错,远程帮忙修复方案分享

第一步,确保MySQL的innodb_file_per_table选项是开启的(默认就是开启的),这样每个表都有自己独立的.ibd文件。

第二步,在目标数据库里,先创建一个与报错表结构完全一致的空表,我们让同事从备份的SQL脚本里找到了这个表的创建语句(CREATE TABLE语句),或者如果另一个没问题的从库有相同表,也可以从那边获取,创建这个空表非常关键,它的结构必须和原表一分不差。

第三步,丢弃这个新创建的空表的表空间,执行命令ALTER TABLE tablename DISCARD TABLESPACE;,这个操作会删除这个空表刚生成的.ibd文件,相当于告诉MySQL:“这个表的结构我记住了,但数据文件我先不要了”。

MySQL升级时遇到表空间获取失败报错,远程帮忙修复方案分享

第四步,从数据库的数据目录中,找到那个报错的、被“遗弃”的原始表的.ibd文件,我们让他先把这个文件复制一份做备份,以防万一,将这个原始的.ibd文件拷贝到新建的那个空表所在的位置,并确保文件权限正确。

第五步,也是最关键的一步,将这个“.ibd”文件“导入”给新表,执行命令ALTER TABLE tablename IMPORT TABLESPACE;,这个命令就是让MySQL去读取这个外来的.ibd文件,并尝试将其与当前的表结构绑定。

执行完这个操作后,我们怀着紧张的心情让同事尝试查询一下这张表,当查询结果正常返回,数据一条没少的时候,电话两头的人都松了一口气,我们接着对另外几张报同样错误的表如法炮制,都成功恢复了。 来源:总结自多次危机处理后的复盘会议记录)

整个远程修复过程持续了大概两个小时,核心就是冷静分析日志、逐步排除可能性,并运用对InnoDB存储机制的理解来解决问题,事后我们复盘,这次问题的根本原因可能是升级过程中服务器曾出现过短暂的磁盘I/O瓶颈,导致部分表的元数据写入数据字典时出现了异常,这次经历也给我们提了个醒:第一,数据库升级前一定要做完整的数据备份,并且验证备份的可恢复性,这是最后的救命稻草,第二,升级操作尽量选择业务低峰期,并确保服务器资源充足,第三,升级后要有详细的应用功能和数据一致性验证流程,不能只满足于服务启动成功,虽然远程解决问题增加了沟通成本,但只要思路清晰,指令明确,同样可以高效地化解危机。