生产环境遇到MySQL数据页损坏问题如何解决?
创始人
2024-04-29 13:22:03
0

原标题:生产环境遇到MySQL数据页损坏问题如何解决?

者:徐文梁

爱可生 DBA 成员,一个执着于技术的数据库工程师,主要负责数据库日常运维工作。擅长 MySQL,Redis 及其他常见数据库也有涉猎;喜欢垂钓,看书,看风景,结交新朋友。

本文来源:可生开源社区

1问题背景

四月份的时候,遇到一次实例异常 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 要有忧患意识,必须要提前准备好应对之策,针对此类问题,该如何排查以及解决?通过查阅资料和向前辈请教,也算有所收获,想着如果有其他同学遇到类似问题也可作为参考,于是有了此文。

2问题分析

一般来说,数据页损坏,错误日志中都会显示具体的 page number,其他情况暂不考虑。在此前提下,根据实例状态可以将数据页损坏分为以下两种场景:

  1. 实例能正常启动

  2. 实例无法正常启动

场景不同,处理方法也略有不同,下面分别展开详细分析:

场景一:实例能正常启动

此时借助通过错误日志中的信息,可以通过查询元数据表获取数据页所属信息。考虑生产环境信息安全,在测试环境建立测试表进行展示。

测试环境表结构如下:

mysql> usetest;

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with-A

Databasechanged

mysql> showcreatetablet_user\G;

*************************** 1. row ***************************

Table: t_user

CreateTable: CREATETABLE`t_user`(

`id`bigint( 20) NOTNULLAUTO_INCREMENT,

`name`varchar( 255) DEFAULTNULL,

`age`tinyint( 4) DEFAULTNULL,

`create_time`datetime DEFAULTNULL,

`update_time`datetime DEFAULTNULL,

PRIMARY KEY( `id`),

KEY`idx_name`( `name`)

) ENGINE= InnoDBAUTO_INCREMENT= 178120DEFAULTCHARSET=utf8

1rowinset( 0.00sec)

ERROR:

Noqueryspecified

根据错误信息中提示的 page number信息来查看数据页信息,查询方式如下:

mysql> useinformation_schema;

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with-A

Databasechanged

mysql> select* fromINNODB_BUFFER_PAGE wherePAGE_NUMBER= 1156limit10;

+ ---------+----------+-------+-------------+-----------+------------+-----------+-----------+---------------------+---------------------+-------------+-----------------+------------+----------------+-----------+-----------------+------------+---------+--------+-----------------+

| 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.18sec)

注意:查询 INNODB_BUFFER_PAGE 系统表[1] 会对性能有影响,因此不建议随意在生产环境执行。

另外,如果错误日志中有提示 space id 和 index id 相关信息,则也可以通过如下方式(涉及 INNODB_SYS_INDEXES[2] 和 INNODB_SYS_TABLES[3] 系统表 )进行查询:

mysql> selectb.INDEX_ID, a.NAME asTableName, a.SPACE asSpace,b.NAME asIndexName fromINNODB_SYS_TABLES a,INNODB_SYS_INDEXES b wherea.SPACE =b.SPACE anda.SPACE= 126andb.INDEX_ID= 225;

+ ----------+-------------+-------+-----------+

| INDEX_ID | TableName | Space | IndexName |

+ ----------+-------------+-------+-----------+

| 225 | test/t_user | 126 | idx_name |

+ ----------+-------------+-------+-----------+

1 row in set( 0.01sec)

根据上面的查询结果,确定损坏的页是属于主键还是辅助索引,如果属于主键索引,因为在 MySQL 中索引即数据,则可能会导致数据丢失,如果是辅助索引,删除索引重建即可。

场景二:实例无法正常启动

此时可以通过两种方式尝试拉起实例。

方法一

使用 innodb_force_recovery[4] 参数进行强制拉起 MySQL 实例。

正常情况下 innodb_force_force_recovery 值应该设置为 0。当紧急情况下实例无法正常启动时可以尝试将其设置为 >0 的值,强制拉起实例然后将数据逻辑备份导出进行恢复。innodb_force_recovery 值最高支持设置到 6,但是值为 4 或更大可能会永久损坏数据文件。因此当强制 InnoDB 恢复时,应始终以 innodb_force_recovery=1 开头,并仅在必要时递增该值。

方法二

使用 inno_space[5] 工具进行数据文件进行修复。

inno_space是一个可以直接访问 InnoDB 内部文件的命令行工具,可以通过该工具查看 MySQL 数据文件的具体结构,修复 corrupt page。更多参考[6]

如果 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 服务。

3问题总结

经过前面分析,了解数据页损坏场景的处理方式。哪怕极端场景下,也可以做到从容不慌,尽可能少丢数据甚至能够不丢数据。但是如果是生产环境,尤其是金融行业,是无法容忍丢失一条数据的,比较有可能这一条数据就涉及几个小目标呢,因此,重要的事情说三遍,一定要备份!一定要备份!一定要备份!

参考资料

[1]

innodb_buffer_page: https://dev.mysql.com/doc/refman/5.7/en/information-schema-innodb-buffer-page-table.html

[2]

innodb_sys_indexes: https://dev.mysql.com/doc/refman/5.7/en/information-schema-innodb-sys-indexes-table.html

[3]

innodb_sys_table: https://dev.mysql.com/doc/refman/5.7/en/information-schema-innodb-sys-tables-table.html

[4]

innodb_force_recovery: https://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html

[5]

inno_space: https://github.com/baotiao/inno_space

[6]

inno_space 工具介绍: http://mysql.taobao.org/monthly/2021/11/02/

🕰 8 月 26 日 14:00-18:00

🏡 北京中关村创业大街 12 号楼 5 层

🔥 一起聊聊 AI 大模型与底层技术

🎁 现场抽奖,福利多多

微软Excel集成Python,龟叔参与架构制定

一份基于开源软件的解决方案,坑了我 2 万元 !

中国程序员拒写赌博程序被拔14颗牙,全身损伤达88%

这里有最新开源资讯、软件更新、技术干货等内容

点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦

相关内容

干燥综合症最新治疗进展 干...
干燥综合症最新治疗方法包括局部治疗和全身治疗。局部治疗包括人工泪液...
2024-11-08 13:50:51
第十六届中国国际种业博览会...
10月30日上午,第十六届中国国际种业博览会暨第二十一届全国种子信...
2024-10-31 14:11:28
学习《决定》每日问答丨如何...
新华社北京10月30日电《中共中央关于进一步全面深化改革、推进中国...
2024-10-31 08:02:27
DIKANG白色药片是什么...
dikang白色药片是一种中药配方颗粒。 dikang白色药片是由...
2024-10-24 00:01:44
加力推出一揽子增量政策!这...
10月8日,国务院新闻办公室举行新闻发布会,国家发展改革委主任郑栅...
2024-10-09 14:57:31
国家医保局:进一步做好医保...
央视网消息:据国家医保局网站消息,今年4月以来,国家医保局开展医保...
2024-09-30 18:01:31

热门资讯

存款利息怎么算?湖南农商行存款... 导读湖南农商行存款利息怎么算?湖南农商行作为湖南最大的股份制银行,它是一家地方性、集约化、国际化、股...
新农保一年缴费180元60岁后... 导读新农保一年缴费180元,60岁后能拿多少钱呢?我们这一个月是208块。农村大多是买这种农保吧,刚...
金三角李国辉,率领三千残部打败... 原标题:金三角李国辉,率领三千残部打败泰国政府军,到台湾后结局如何? 解放战争...
上海发布:紧挨着城区的六个村为... 原标题:上海发布:紧挨着城区的六个村为何一定要保留?来看闵行的城乡融合发展之路 ...
使命:林荫不做市公安局局长,为... 原标题:使命:林荫不做市公安局局长,为何副局长牛明也不可能接任 林荫从白山地区...
茫崖市有多孤独?方圆百里荒无人... 原标题:茫崖市有多孤独?方圆百里荒无人烟,我国为何要建在戈壁之中? 这是中国最...
邢台农商银行存款利率表:一年期... 导读邢台农商银行现在的利率表:一年期2.25二年期2.85三年期3.45。农商银行原来的利息比这高好...
杨虎城去世后,他的子女结局如何... 原标题:杨虎城去世后,他的子女结局如何? 1936年12月12日,著名爱国将领...
孙中山与黄兴为何会分道扬镳?两... 原标题:孙中山与黄兴为何会分道扬镳?两个事件促使他们关系破裂 现在说到辛亥革命...
哈以战争为何爆发?美国掌握军权... 原标题:哈以战争为何爆发?美国掌握军权的盎撒集团要收回犹太集团所控制的经济权利 ...