Docker容器MySQL5.7系统表空间数据文件ibdata1

环境信息

  • 主机:Ubuntu 20.04.2 LTS
    Docker容器MySQL5.7系统表空间数据文件ibdata1

  • Docker: 20.10.6
    Docker容器MySQL5.7系统表空间数据文件ibdata1

  • 镜像版本: mysql:5.7.19

ibdata file

在MySQL数据目录下,文件名称形如 ibdata1, ibdata2 之类的数据文件组成了 InnoDB 系统表空间。

Reference click here

ibdata 保存了什么?

当你开启了 innodb_file_per_table (MySQL5.6之后默认开启),表被存储在他们自己的表空间里(数据和索引),但是系统表空间仍然在存储其它的 InnoDB 内部数据:

  • Data dictionary: 数据字典,也就是 InnoDB 表的元数据
  • 变更缓冲区
  • Double write buffer: 双写缓冲区
  • UNDO space: 撤销日志

检查什么被存储到了 ibdata1 里了?

本文主要介绍如何用 innochecksum 来查看什么被存储到 ibdata1 共享表空间的信息。

坑1: page 0 invalid (fails old style checksum)

我首先是参考 《MySQL的ibdata1详解》 提供的马克·卡拉汉制作的一个修改版 innochecksum ,它发布在这个漏洞报告里。我也确实下载、编译、执行了,但是现在这种方法已经行不通了。下面内容仅仅是记录一下思路:

下载编译: 下载得到的 innochecksum.c.orig 是 C 语言源程序,需要 重命名 然后 编译一下

mv innochecksum.c.orig innochecksum.c
gcc innochecksum.c -o innochecksum

这样就可以得到可执行文件 innochecksum 了。
Docker容器MySQL5.7系统表空间数据文件ibdata1

找到 ibdata1: 我们需要知道 Docker 容器挂载在当前主机的那个目录下,可以参考《查看Docker默认的volume地址》:

docker ps -a
docker container inspect mysql容器ID | grep Mounts -A 20

Docker容器MySQL5.7系统表空间数据文件ibdata1
这样我们知道主机上的文件位置 Source 与 Docker 容器的文件位置是对应的。因此,ibdata1 存在于 Source 所代表的本机地址中。所以我的 ibdata1 文件在主机上的地址就是
/var/lib/docker/volumes/6cabb5980aa5e859e4fe389f8ed6dcfede8c126b696edb8e777addac800996e1/_data/ibdata1

运行 innochecksum: 我们使用 innochecksum 工具来查看 ibdata1

sudo innochecksum的文件地址 ibdata1在主机上的地址

Docker容器MySQL5.7系统表空间数据文件ibdata1

但是,使用这种方法会出现 page 0 invalid (fails old style checksum) 这个错误。

★ 为什么会出现这个错误呢?

因为这个版本太老了,这个 BUG 的修复版本是 5.0.+,我们现在的 MySQL 已经是 5.7.+ ,出现不兼容的情况也很正常。你可以看一下对应的时间。
Docker容器MySQL5.7系统表空间数据文件ibdata1

坑2:Unable to lock file:: /var/lib/mysql/ibdata1

在遇到“坑1”之后,我一度有点纠结该如何处理,我尝试从主机登录到 Docker 容器中:

docker restart Docker容器ID
docker container exec -it Docker容器ID /bin/bash

Docker容器MySQL5.7系统表空间数据文件ibdata1

查看 innochecksum 的版本:

innochecksum --version

Docker容器MySQL5.7系统表空间数据文件ibdata1
我无意间发现 innochecksum 是可用的,应该是默认安装了。

尝试使用 innochecksum 查看 ibdata1:

innochecksum /var/lib/mysql/ibdata1

Docker容器MySQL5.7系统表空间数据文件ibdata1

但是,结果不尽如人意,出现了 Error: Unable to lock file:: /var/lib/mysql/ibdata1,解决方案是 停止当前的 mysql 服务

停止 MySQL 服务:

service mysql stop

但是,停止后,会退出 Docker 容器的 Bash,回到主机的 Bash 中。

解决方案

所以,我想到有没有可能把 Docker 容器中的 innochecksum 拷贝到主机中,然后在主机执行 innochecksum?

把docker容器内部的文件复制到本地:

docker cp 容器id或名称:/path/filename /path/filename

查看 innochecksum 在容器中的存储位置:

which innochecksum 

Docker容器MySQL5.7系统表空间数据文件ibdata1

所以,最终把docker容器内部的文件复制到本地的命令是

cd /var/lib/docker/volumes/6cabb5980aa5e859e4fe389f8ed6dcfede8c126b696edb8e777addac800996e1/_data/
sudo docker cp 1626394823f9:/usr/bin/innochecksum ./

现在 innochecksum 和 ibdata1 在同一个目录下了。

使用 innochecksum 查看 Page 类型摘要:

sudo ./innochecksum -S ibdata1

Docker容器MySQL5.7系统表空间数据文件ibdata1

除了 MySQL 正在运行时,Unable to lock file;假如没有权限,也可能导致 Unable to lock file。因此我加上了 sudo

使用 innochecksum 查看 Page 总页数:

sudo ./innochecksum -c ibdata1

Docker容器MySQL5.7系统表空间数据文件ibdata1

现在可以计算出 Undo log page 占 总页数的比例是 38808 / 41728 = 93%

innochecksum的更多参数

MySQL 5.7.19 附带的 innochecksum 支持以下参数 (通过 ./innochecksum 查看):
Docker容器MySQL5.7系统表空间数据文件ibdata1

参考文档

Docker容器MySQL5.7系统表空间数据文件ibdata1

上一篇:MongoDB(10)- 查询嵌套文档


下一篇:MySql的四种隔离级别