生产环境遇到MySQL数据页损坏问题如何解决?
当数据页破坏,如何根据实例的健康状况选择不同的策略定位损坏文件并恢复。
作者:徐文梁
爱可生 DBA 成员,一个执着于技术的数据库工程师,主要负责数据库日常运维工作。擅长 MySQL,Redis 及其他常见数据库也有涉猎;喜欢垂钓,看书,看风景,结交新朋友。
本文来源:原创投稿
- 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
问题背景
四月份的时候,遇到一次实例异常 crash 的问题。当时数据库自动重启,未对生产造成影响,未做处理,但是还是记录了下错误信息,错误日志中有如下信息:
InnoDB: End of page dump InnoDB: Page may be an index page where index id is 8196 2023-04-11T07:57:42.508371+08:00 0 [ERROR] [FATAL] InnoDB: Apparent corruption of an index page [page id: space=3859, page number=842530] to be written to data file. We intentionally crash the server to prevent corrupt data from ending up in data files. 2023-04-11 07:57:42 0x7fe4d42cf080 InnoDB: Assertion failure in thread 140620788985984 in file ut0ut.cc line 921 InnoDB: We intentionally generate a memory trap.
因为当时自动恢复了,并未重视这个问题,然后六月份的时候实例又 crash 了。查看报错信息,报错信息如下:
2023-06-23T04:32:36.538380+08:00 0 [ERROR] InnoDB: Probable data corruption on page 673268. Original record on that page; (compact record)2023-06-23T04:32:36.538426+08:00 0 [ERROR] InnoDB: Cannot find the dir slot for this record on that page; (compact record)2023-06-23 04:32:36 0x7fe2bf68f080 InnoDB: Assertion failure in thread 140611850662016 in file page0page.cc line 153 InnoDB: We intentionally generate a memory trap.
两次的报错信息很相似,出现一次是偶然,两次就值得重视了。虽然之前很幸运未对生产造成影响,但是如果后面哪一天异常了导致实例无法启动,那不就是妥妥的一个生产故障嘛,作为 DBA 要有忧患意思,必须要提前准备好应对之策,针对此类问题,该如何排查以及解决?通过查阅资料和向前辈请教,也算有所收获,想着如果有其他同学遇到类似问题也可作为参考,于是有了此文。
问题分析
一般来说,数据页损坏,错误日志中都会显示具体的 page number,其他情况暂不考虑。在此前提下,根据实例状态可以将数据页损坏分为以下两种场景:
- 实例能正常启动
- 实例无法正常启动
场景不同,处理方法也略有不同,下面分别展开详细分析:
场景一:实例能正常启动
此时借助通过错误日志中的信息,可以通过查询元数据表获取数据页所属信息。考虑生产环境信息安全,在测试环境建立测试表进行展示。
测试环境表结构如下:
mysql> use test; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show create table t_user\G; *************************** 1. row *************************** Table: t_user Create Table: CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` tinyint(4) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=178120 DEFAULT CHARSET=utf8 1 row in set (0.00 sec) ERROR: No query specified
根据错误信息中提示的 page number 信息来查看数据页信息,查询方式如下:
mysql> use information_schema; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select * from INNODB_BUFFER_PAGE where PAGE_NUMBER=1156 limit 10; +---------+----------+-------+-------------+-----------+------------+-----------+-----------+---------------------+---------------------+-------------+-----------------+------------+----------------+-----------+-----------------+------------+---------+--------+-----------------+ | POOL_ID | BLOCK_ID | SPACE | PAGE_NUMBER | PAGE_TYPE | FLUSH_TYPE | FIX_COUNT | IS_HASHED | NEWEST_MODIFICATION | OLDEST_MODIFICATION | ACCESS_TIME | TABLE_NAME | INDEX_NAME | NUMBER_RECORDS | DATA_SIZE | COMPRESSED_SIZE | PAGE_STATE | IO_FIX | IS_OLD | FREE_PAGE_CLOCK | +---------+----------+-------+-------------+-----------+------------+-----------+-----------+---------------------+---------------------+-------------+-----------------+------------+----------------+-----------+-----------------+------------+---------+--------+-----------------+ | 0 | 64 | 126 | 1156 | INDEX | 0 | 0 | NO | 0 | 0 | 0 | `test`.`t_user` | idx_name | 515 | 15965 | 0 | FILE_PAGE | IO_NONE | NO | 0 | +---------+----------+-------+-------------+-----------+------------+-----------+-----------+---------------------+---------------------+-------------+-----------------+------------+----------------+-----------+-----------------+------------+---------+--------+-----------------+ 1 row in set (0.18 sec)
注意:查询 INNODB_BUFFER_PAGE 系统表 会对性能有影响,因此不建议随意在生产环境执行。
另外,如果错误日志中有提示 space id
和 index id
相关信息,则也可以通过如下方式(涉及 INNODB_SYS_INDEXES 和 INNODB_SYS_TABLES 系统表 )进行查询:
mysql> select b.INDEX_ID, a.NAME as TableName, a.SPACE as Space,b.NAME as IndexName from INNODB_SYS_TABLES a,INNODB_SYS_INDEXES b where a.SPACE =b.SPACE and a.SPACE=126 and b.INDEX_ID=225; +----------+-------------+-------+-----------+ | INDEX_ID | TableName | Space | IndexName | +----------+-------------+-------+-----------+ | 225 | test/t_user | 126 | idx_name | +----------+-------------+-------+-----------+ 1 row in set (0.01 sec)
根据上面的查询结果,确定损坏的页是属于主键还是辅助索引,如果属于主键索引,因为在 MySQL 中索引即数据,则可能会导致数据丢失,如果是辅助索引,删除索引重建即可。
场景二:实例无法正常启动
此时可以通过两种方式尝试拉起实例。
方法一
使用 innodb_force_recovery 参数进行强制拉起 MySQL 实例。
正常情况下可以 innodb_force_force_recovery
值应该设置为 0。当紧急情况下实例无法正常启动时可以尝试将其设置为 >0 的值,强制拉起实例然后将数据逻辑备份导出进行恢复。innodb_force_recovery
值最高支持设置到 6,但是值为 4 或更大可能会永久损坏数据文件。因此当强制 InnoDB 恢复时,应始终以 innodb_force_recovery=1
开头,并仅在必要时递增该值。
方法二
使用 inno_space 工具进行数据文件进行修复。
inno_space 是一个可以直接访问 InnoDB 内部文件的命令行工具,可以通过该工具查看 MySQL 数据文件的具体结构,修复
corrupt page
。更多参考
如果 InnoDB 表文件中的 page 损坏,导致实例无法启动,可以尝试通过该工具进行修复,如果损坏的只是 leaf page
,inno_space 可以将 corrupt page
跳过,从而保证实例能够启动,并且将绝大部分的数据找回。示例:
# 假设 MySQL 错误日志中有类似报错如下: [ERROR] [MY-030043] [InnoDB] InnoDB: Corrupt page resides in file: .test/t_user.ibd, offset: 163840, len: 16384 [ERROR] [MY-011906] [InnoDB] Database page corruption on disk or a failed file read of page [page id: space=126, page number=1158]. You may have to recover from a backup. # 通过如下方式进行修复: # 删除损坏的数据页中损坏部分。 ./inno -f /opt/mysql/data/3307/test/t_user.ibd -d 10 # 更新损坏的数据页中 checksum 值。 ./inno -f /opt/mysql/data/3307/test/t_user.ibd -u 10 启动 MySQL 服务。
问题总结
经过前面分析,了解数据页损坏场景的处理方式。哪怕极端场景下,也可以做到从容不慌,尽可能少丢数据甚至能够不丢数据。但是如果是生产环境,尤其是金融行业,是无法容忍丢失一条数据的,比较有可能这一条数据就涉及几个小目标呢,因此,重要的事情说三遍,一定要备份!一定要备份!一定要备份!
更多技术文章,请访问:https://opensource.actionsky.com/
关于 SQLE
爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。
SQLE 获取
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Spring 6.1 已兼容虚拟线程和 JDK 21
Spring Framework 昨日更新的文档显示,Spring 6.1 已全面兼容虚拟线程 (Virtual Threads) 和 JDK 21。 虚拟线程配置选项:专用的VirtualThreadTaskExecutor和SimpleAsyncTaskExecutor 上的虚拟线程模式,以及类似的具有 new-thread-per-task strategy 和虚拟线程模式的 SimpleAsyncTaskScheduler。 延伸阅读:Java 下一代高并发技术 —— 虚拟线程 “JEP 425: Virtual Threads (Preview)”
- 下一篇
一条提示词等同于多少个数据点?
数据点(data points)通常用于描述单个信息单位或观测值,在本文中,它被用来量化“提示词”方法相对于传统方法的效率和效果。文章比较了两种训练(微调)机器学习模型的方法:一种是使用提示(prompts),本文也称之“提示词”,另一种是使用传统的分类器头 (classifier heads),本文也称之为“分类头”。通过比较可以发现,使用提示词的方法通常比使用分类器头的方法更好。 本文由 Hugging Face 的研究员 Teven Le Scao 撰写,并于 2021 年 4 月发表。尽管已经过去了很久,但其中的研究方法和发现仍具有深远的学术价值和实际应用意义,特别是对于理解和使用自然语言提示在机器学习中的角色。 本文原文是以 Hugging Face Space 应用做的展现,对于很多结果可以进行更高级的交互,请在文末查看本文的中英文原文。 当前 NLP 应用的主流方法是针对各式各样的特定任务,分别对预训练语言模型的分类头进行微调。随着语言模型变得越来越大,各种替代方法相继涌现,开始叫板在 BERT、UniLM 以及 GPT 中广泛使用的分类头法。特别地,GPT-3 向大家普...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS6,7,8上安装Nginx,支持https2.0的开启