Docker容器MySQL5.7系统表空间数据文件ibdata1
环境信息
-
主机:Ubuntu 20.04.2 LTS
-
Docker: 20.10.6
-
镜像版本: 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
了。
★ 找到 ibdata1: 我们需要知道 Docker 容器挂载在当前主机的那个目录下,可以参考《查看Docker默认的volume地址》:
docker ps -a
docker container inspect mysql容器ID | grep Mounts -A 20
这样我们知道主机上的文件位置 Source 与 Docker 容器的文件位置是对应的。因此,ibdata1
存在于 Source 所代表的本机地址中。所以我的 ibdata1 文件在主机上的地址就是
/var/lib/docker/volumes/6cabb5980aa5e859e4fe389f8ed6dcfede8c126b696edb8e777addac800996e1/_data/ibdata1
★ 运行 innochecksum: 我们使用 innochecksum 工具来查看 ibdata1
sudo innochecksum的文件地址 ibdata1在主机上的地址
但是,使用这种方法会出现 page 0 invalid (fails old style checksum)
这个错误。
★ 为什么会出现这个错误呢?
因为这个版本太老了,这个 BUG 的修复版本是 5.0.+,我们现在的 MySQL 已经是 5.7.+ ,出现不兼容的情况也很正常。你可以看一下对应的时间。
坑2:Unable to lock file:: /var/lib/mysql/ibdata1
在遇到“坑1”之后,我一度有点纠结该如何处理,我尝试从主机登录到 Docker 容器中:
docker restart Docker容器ID
docker container exec -it Docker容器ID /bin/bash
★ 查看 innochecksum 的版本:
innochecksum --version
我无意间发现 innochecksum 是可用的,应该是默认安装了。
★ 尝试使用 innochecksum 查看 ibdata1:
innochecksum /var/lib/mysql/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容器内部的文件复制到本地的命令是
cd /var/lib/docker/volumes/6cabb5980aa5e859e4fe389f8ed6dcfede8c126b696edb8e777addac800996e1/_data/
sudo docker cp 1626394823f9:/usr/bin/innochecksum ./
现在 innochecksum 和 ibdata1 在同一个目录下了。
★ 使用 innochecksum 查看 Page 类型摘要:
sudo ./innochecksum -S ibdata1
除了 MySQL 正在运行时,Unable to lock file;假如没有权限,也可能导致 Unable to lock file。因此我加上了 sudo
★ 使用 innochecksum 查看 Page 总页数:
sudo ./innochecksum -c ibdata1
现在可以计算出 Undo log page 占 总页数的比例是 38808 / 41728 = 93%
innochecksum的更多参数
MySQL 5.7.19 附带的 innochecksum 支持以下参数 (通过 ./innochecksum
查看):
参考文档
- 浅谈MySQL中的ibdata1 跳转 click here
- MySQL的ibdata1详解 跳转 click here
- docker学习13-docker容器的文件导入和导出 跳转 click here