innodb实例损坏情况下恢复数据及相关工具的开发

作者介绍:谢浩,现任职于云和恩墨(北京)信息技术有限公司,具有多年oracle数据库企业级运维经验,擅长结合业务、硬件系统制定各种项目方案,具有丰富mysql相关的工作经验。

假设你在使用MySQL中的InnoDB驱动,由于遇到了驱动程序错误,内核错误,电源故障或某些罕见的MySQL错误,而在InnoDB ibdata1文件损坏,实例不能启动。你该怎么办呢?

案例描述

某门户mysql innodb数据库实例损坏,数据库服务无法启动,使用文件系统上的数据库frm及bid文件恢复数据库内的业务数据。

相关知识点

Mysql innodb数据库将实例的基础字典信息存储在data目录下的ibdata1文件以及mysql实例中,可以将其理解为oracle数据库的system表空间以及数据字典,如果损坏数据实例将无法启动。

Mysql innodb引擎打开innodb_file_per_table后,每个表都会单独存放在一个表空间中,包含了tablename.frm和tablename.ibd文件,其中.frm后缀的文件记录表的结构信息,.ibd后缀的文件记录表的数据。在mysql实例无法启动的情况下使用这两个文件可以恢复数据库内的业务数据。

恢复过程中需要获得每个数据表的字段个数和每个表空间文件的table id(5.5版本),其中字段个数记录在frm文件中。

1、分析frm文件格式获得表字段个数

分析mysql源代码中位于table.cc文件中的open_binary_frm函数获得frm文件中记录字段数的位置:

open_binary_frm函数中位于table.cc文件第766行调用了get_from_pos函数,该函数负责计算frm文件内字段信息集合的起始偏移量:

该函数中首先seek到file head+64,然后读取“(head+4的dword)+(head+8的dword)*4”的数据,最后pos=buf+length,这里之所以不直接读取,是因为读到的位置可能不是双数,因此要从第64字节读取后整个buffer进行小头转换再读取最后的目标pos。

对该段代码进行解释,pos的值就是frm文件从第64字节开始,跳过head+4的dword内记录的字节数后读取(head+8的dword)*4个字节内的值。

举例说明:

第4、5字节为03 00,小头转换后为0003,第8、9字节为01 00,转换后为00 01。按上述算法,从第64字节开始读取3+1*4=7个字节,读取后进行小头转换为“2F 2F 00 00 00 20 00”,最后截取第3到结束为“00 00 20 00”等于10进制的8192,这就是frm文件中字段信息的保存起始偏移量。

再次观察open_binary_frm函数,我们需要的表字段数实际上是记录在字段信息的保存起始偏移量+258位置:

在本例中为8192+258=8450=0x2102的位置

04 00小头转换后为0004,表示该表有4个字段。

至此字段数量信息读取完成。

2、获得表对应的space_id

space_id 可以从ibd文件的第38~39字节、42~43字节两处处获得:

两处完全一样,读取其中一个即可。

手工恢复流程

1、模拟数据库字典信息损坏

将数据库data目录下ibdata文件改名为ibdata.1,此时启动数据库服务失败,err日志中出现以下信息:

2、在辅助实例生成数据表ddl语句

在目标库建立与原库名称相同字段数量相同的表(字段名任意),将原库frm文件复制到辅助实例,并设置innodb_force_recovery==6

3、在目标实例创建空表并分离数据

执行上述create table命令,对齐space_id,并执行表空间分离

4、使用原frm、ibd文件覆盖目标库同名文件

停止目标实例服务,将需要恢复的原数据库内的frm、ibd文件覆盖目标实例的同名文件,并import表空间:

恢复流程整理及相关工具开发

恢复过程中重要点如下:

1、批量快速获得表的字段数

生产系统包含大量数据表,人工逐个分析frm文件速度慢,需要开发工具批量自动获取。

2、批量获得space_id并生成对齐语句

Space_id的对齐是指在目标库某个表在全实例被创建的顺位必须相同(5.5版本,5.6及以上版本不需要),比如某个表在原库的space_id=100,在目标库上必须先建立99个空表,再建立这个表就能使该表的space_id相同。核心逻辑如下:

3、原地恢复

生产系统数据表数量多、体积大,全部复制到目标实例data目录下时间太长,因此需要将目标实例的data目录指向原实例,同时需要批量将原实例data目录下的所有文件改名。部分代码如下:

流程梳理

1、建立辅助实例、目标实例(人工)

2、批量获得原库表字段个数、space_id(工具)

3、辅助实例批量生成create table语句并自动生成space_id对齐(建空表)语句(工具)

4、目标库文件改名、目标库使用生成的createtable语句建立空表(工具)

5、目标库覆盖(工具)

原文发布于微信公众号 - 数据和云(OraNews)

原文发表时间:2018-02-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏架构之路

【网络编程系列】二:socket通信原理及实践

我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或...

4666
来自专栏惨绿少年

Redis 数据库

1.1 Redis简介 ? 1.1.1 介绍 Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对(key-value)存储数据库...

53413
来自专栏安富莱嵌入式技术分享

【RL-TCPnet网络教程】第20章 RL-TCPnet之BSD Socket客户端

本章节为大家讲解RL-TCPnet的BSD Socket,学习本章节前,务必要优先学习第18章的Socket基础知识。有了这些基础知识之后,再搞本章节会有事半功...

822
来自专栏大内老A

.NET Core采用的全新配置系统[8]: 如何实现配置与源文件的同步

配置的同步涉及到两个方面:第一,对原始的配置文件实施监控并在其发生变化之后从新加载配置;第二,配置重新加载之后及时通知应用程序进而使后者能够使用最新的配置。接下...

17310
来自专栏Java成长之路

十三、JDK的命令行工具

前面的博文我们介绍了一些关于jvm的一些基础知识,本文介绍一些jdk的命令行工具,通过这些工具我们可以对运行日志、异常堆栈、GC日志、线程快照(threaddu...

1022
来自专栏大学生计算机视觉学习DeepLearning

c++ 网络编程(二)TCP/IP linux 下多进程socket通信 多个客户端与单个服务端交互代码实现回声服务器

原文链接:https://www.cnblogs.com/DOMLX/p/9612820.html

1058
来自专栏Spark学习技巧

Kafka源码系列之topic创建分区分配及leader选举

一,基本介绍 本文讲解依然是基于kafka源码0.8.2.2。假如阅读过前面的文章应该知道,用户的admin指令都是通过Zookeeper发布给kafka的Co...

5376
来自专栏Java Edge

操作系统之文件管理一、文件与文件系统二、文件控制块和文件目录三、文件的物理结构四、文件系统的实现五、文件系统实例(UNIX)六、UNIX文件系统一、文件系统实例(FAT)二、文件操作的实现三、文件系统

3376
来自专栏Linux驱动

4.查询方式来写按键驱动程序(详解)

本节目标:    写second程序,内容:通过查询方式驱动按键 1.写出框架 1.1写file_oprations结构体,second_drv_open函数,...

1978
来自专栏技术小黑屋

Ruby执行shell命令的六种方法

在Ruby中,执行shell命令是一件不奇怪的事情,Ruby提供了大概6种方法供开发者进行实现。这些方法都很简单,本文将具体介绍一下如何在Ruby脚本中进行调用...

762

扫码关注云+社区