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 条评论
登录 后参与评论

相关文章

来自专栏IT派

Python 的异步 IO:Asyncio 简介

所谓「异步 IO」,就是你发起一个 IO 操作,却不用等它结束,你可以继续做其他事情,当它结束时,你会得到通知。

683
来自专栏用户2442861的专栏

linux 网络编程 I/O复用 select,poll ,epoll

http://blog.csdn.net/zs634134578/article/details/19929449

1712
来自专栏程序员的碎碎念

从Thinkphp5看RCUD

基础知识 看这篇文章前,你需要理解thinkphp5的几个概念 入口文件:ThinkPHP采用单一入口模式进行项目部署和访问,无论完成什么功能,一个应用都有一个...

3497
来自专栏IT可乐

Nginx(三)------nginx 反向代理

  Nginx 服务器的反向代理服务是其最常用的重要功能,由反向代理服务也可以衍生出很多与此相关的 Nginx 服务器重要功能,比如后面会介绍的负载均衡。本篇博...

762
来自专栏漏斗社区

工具| 诸神之眼nmap定制化之并发处理

当我们使用nmap来进行大规模探测的时候,速度和准确度是摆在我们面前的两个问题,这时需要考虑到nmap的并发处理能力。 0x01 nmap本身的并发执行 相关...

3505
来自专栏散尽浮华

redis cluster集群管理工具redis-trib.rb命令小结-运维笔记

redis-trib.rb是redis官方推出的管理redis集群的工具,集成在redis的源码src目录下,是基于redis提供的集群命令封装成简单、便捷、实...

1073
来自专栏技术记录

RunTime.getRuntime().exec()运行脚本命令介绍和阻塞

 java在企业级项目开发中,无论是强制性的功能需要,还是为了简便java的实现,需要调用服务器命令脚本来执行。在java中,RunTime.getRuntim...

2899
来自专栏大内老A

[WCF 4.0新特性] 标准终结点与无(.SVC)文件服务激活

今天介绍WCF 4.0的另外两个新特性:标准终结点(Standard Endpoint)和无(.SVC)文件服务激活(File-Less Activation)...

22010
来自专栏Django Scrapy

Linux 目录结构及文件基本操作

win和类unix系统的文件目录的区别 一种不同是体现在目录与存储介质(磁盘,内存,DVD 等)的关系上,以往的 Windows 一直是以存储介质为主的,主要...

2966
来自专栏北京马哥教育

77%的Linux运维都不懂的内核问题

2178

扫码关注云+社区