数据库内核月报 - 2015 / 05-MySQL · 捉虫动态 · 5.6 与 5.5 InnoDB 不兼容导致 crash

简介:

bug 背景

RDS的备份工具用的是 Percona-XtraBackup(后面简称PXB),这个工具包里有2个重要的工具,innobackupex和xtrabackup,后者是C编译出的二进制文件,负责备份 InnoDB 数据,前者是一个Perl 脚本,对后者进行封装,同时负责备份非 InnoDB 数据。xtrabackup 二进制里内嵌了InnoDB引擎,所以能很好的处理InnoDB数据。在2.2版本之前,PXB 分别针对不同版本的 MySQL 源码(5.1/5.5/5.6)编译了不同版本的xtrabackup,以便备份不同版本的MySQL数据,然而在2.2之后,PXB官方觉得5.6已经可以很好的兼容5.1和5.5,所以就只针对 5.6.22 版本的代码编译了一个 xtrabackup 二进制文件,关于这个改动可以看官方的BP #single binary。故事就由此发生。。。

bug 描述

当我们对5.5版本的备份集进行还原的时候,xtrabackup crash 了,报错信息如下:

2015-05-12 19:03:08 7fd9d8258720  InnoDB: Assertion failure in thread 140573610968864 in file pars0pars.cc line 865
InnoDB: Failing assertion: sym_node->table != NULL
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
11:03:08 UTC - xtrabackup got signal 6 ;
This could be because you hit a bug or data is corrupted.
This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help
diagnose the problem, but since we have already crashed,
something is definitely wrong and this may fail.

Thread pointer: 0x176aeb0
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
stack_bottom = 0 thread_stack 0x10000
xtrabackup(my_print_stacktrace+0x35) [0x9f5331]
xtrabackup(handle_fatal_signal+0x2bb) [0x7f801b]
/lib64/libpthread.so.0() [0x3530c0f500]
/lib64/libc.so.6(gsignal+0x35) [0x35f40328a5]
/lib64/libc.so.6(abort+0x175) [0x35f4034085]
xtrabackup() [0x76bfb0]
xtrabackup(pars_update_statement(upd_node_t*, sym_node_t*, void*)+0x30) [0x76c8d8]
xtrabackup(yyparse()+0xcb1) [0xa5ef27]
xtrabackup(pars_sql(pars_info_t*, char const*)+0xaf) [0x76e06d]
xtrabackup(que_eval_sql(pars_info_t*, char const*, unsigned long, trx_t*)+0x85) [0x78eeb2]
xtrabackup(row_drop_table_for_mysql(char const*, trx_t*, bool, bool)+0xa98) [0x720a0c]
xtrabackup(row_mysql_drop_temp_tables()+0x24c) [0x721503]
xtrabackup(recv_recovery_rollback_active()+0x2c) [0x753ebe]
xtrabackup(innobase_start_or_create_for_mysql()+0x17aa) [0x7293c4]
xtrabackup() [0x607a00]
xtrabackup() [0x610204]
xtrabackup(main+0x8b8) [0x611674]
/lib64/libc.so.6(__libc_start_main+0xfd) [0x35f401ecdd]
xtrabackup() [0x604369]

## bug 分析
从crash的信息InnoDB: Assertion failure in thread 140573610968864 in file pars0pars.cc line 865,可以定位的crash的代码点

862|                sym_node->table = dict_table_open_on_name(
863|                        sym_node->name, TRUE, FALSE, DICT_ERR_IGNORE_NONE);
864|
865|                ut_a(sym_node->table != NULL);

可以看到,是 InnoDB 在试图打开一张表的时候,打开失败,直接 assert 了。

分析调用堆栈,是xtrabackup在恢复数据的时候,启动了内嵌的 InnoDB 引擎,在活跃事务回滚的时候,会将备份时候存在的临时表全部 drop 掉。在删除表的时候,除了要删除表本身,还需要删除在 InnoDB 系统表中的记录,删除记录是通过内部执行sql的方式做的que_eval_sql,其中有这么一段sql

4195|                           "DELETE FROM SYS_TABLESPACES\n"
4196|                           "WHERE SPACE = space_id;\n"
4197|                           "DELETE FROM SYS_DATAFILES\n"
4198|                           "WHERE SPACE = space_id;\n"

SYS_TABLESPACES 和 SYS_DATAFILES 这2个系统表是在5.6中才有的,5.5是没有的,所以在调用 dict_table_open_on_name 的时候就打不开 SYS_TABLESPACES 表,导致CRASH。

bug修复

这里给一个简单的修复方法,就是在调用 que_eval_sql 删除记录前判断下当前数据是否是5.6的,如果是就传原来的sql,如果不是,就传去掉 SYS_TABLESPACES 和 SYS_DATAFILES 的sql。PXB官方已经确认这个bug #1399471,目前尚未修复,应该会在下个版本修掉。
如果等不及的话,可以有2种选择:
1. 代码修复,用这里提供的方法;
2. 版本回退,在恢复的时候,临时用PXB 2.1版本中的 xtrabackup_55 替换 xtrabckup。

bug 影响

从上面的分析可以得到,要触发这个bug,需要这些条件:
1. PXB版本是2.2以上
2. MySQL版本是5.5/5.1
3. 备份的时候有持有临时表的回话。

当满足上面这些条件,恢复数据就会crash。

PXB备份出来的idb数据时间点是不一致的,恢复数据时需要应用redo将数据追到一个一致的点,效果上就相当于 MySQL 异常关闭,buffer pool 有数据没有落盘,然后重启应用redo做崩溃恢复。所以这个场景只有在用PXB才容易出现,对正常使用的mysqld来说一般是不会的,因为我们在升级的时候都是正常关闭 mysqld,这是临时表都被清理干净了,后再用新版mysqld启动,所以新版mysqld启动时就不需要做drop临时表的操作,自然不会crash了。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
3月前
|
存储 关系型数据库 MySQL
介绍MySQL的InnoDB引擎特性
总结而言 , Inno DB 引搞 是 MySQL 中 高 性 能 , 高 可靠 的 存 储选项 , 宽泛 应用于要求强 复杂交易处理场景 。
157 15
|
8月前
|
存储 网络协议 关系型数据库
MySQL8.4创建keyring给InnoDB表进行静态数据加密
MySQL8.4创建keyring给InnoDB表进行静态数据加密
292 1
|
12月前
|
存储 缓存 关系型数据库
【MySQL进阶篇】存储引擎(MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案)
MySQL的存储引擎是其核心组件之一,负责数据的存储、索引和检索。不同的存储引擎具有不同的功能和特性,可以根据业务需求 选择合适的引擎。本文详细介绍了MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案。
2033 57
【MySQL进阶篇】存储引擎(MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案)
|
8月前
|
SQL 缓存 关系型数据库
使用温InnoDB缓冲池启动MySQL测试
使用温InnoDB缓冲池启动MySQL测试
160 0
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
383 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
存储 关系型数据库 MySQL
MySQL存储引擎详述:InnoDB为何胜出?
MySQL 是最流行的开源关系型数据库之一,其存储引擎设计是其高效灵活的关键。InnoDB 作为默认存储引擎,支持事务、行级锁和外键约束,适用于高并发读写和数据完整性要求高的场景;而 MyISAM 不支持事务,适合读密集且对事务要求不高的应用。根据不同需求选择合适的存储引擎至关重要,官方推荐大多数场景使用 InnoDB。
550 7
|
存储 关系型数据库 MySQL
Mysql索引:深入理解InnoDb聚集索引与MyisAm非聚集索引
通过本文的介绍,希望您能深入理解InnoDB聚集索引与MyISAM非聚集索引的概念、结构和应用场景,从而在实际工作中灵活运用这些知识,优化数据库性能。
620 7
|
存储 关系型数据库 MySQL
MySQL引擎InnoDB和MyISAM的区别?
InnoDB是MySQL默认的事务型存储引擎,支持事务、行级锁、MVCC、在线热备份等特性,主索引为聚簇索引,适用于高并发、高可靠性的场景。MyISAM设计简单,支持压缩表、空间索引,但不支持事务和行级锁,适合读多写少、不要求事务的场景。
230 9

相关产品

  • 云数据库 RDS MySQL 版
  • 推荐镜像

    更多