咱们在 Percona 支持栏目常常收到关于 MySQL 的 ibdata1 文件的这个问题。当监控服务器发送一个关于 MySQL 服务器存储的报警时,恐慌就开始了 —— 就是说磁盘快要满了。一番调查后你意识到大多数地盘空间被 InnoDB 的共享表空间 ibdata1 使用。而你已经启用了 innodb_file_per_table,因此问题是:php
当你启用了 innodb_file_per_table
,表被存储在他们本身的表空间里,可是共享表空间仍然在存储其它的 InnoDB 内部数据:html
其中的一些在 Percona 服务器上能够被配置来避免增加过大的。例如你能够经过 innodb_ibuf_max_size 设置最大变动缓冲区,或设置 innodb_doublewrite_file 来将双写缓冲区存储到一个分离的文件。mysql
MySQL 5.6 版中你也能够建立外部的撤销表空间,因此它们能够放到本身的文件来替代存储到 ibdata1。能够看看这个文档。ios
当 MySQL 出现问题一般咱们须要执行的第一个命令是:git
1
|
SHOW ENGINE INNODB STATUS/G
|
这将展现给咱们一些颇有价值的信息。咱们从** TRANSACTION(事务)**部分开始检查,而后咱们会发现这个github
1
2
3
4
|
---TRANSACTION 36E, ACTIVE 1256288 sec
MySQL thread id 42, OS thread handle 0x7f8baaccc700, query id 7900290 localhost root
show engine innodb status
Trx read view will not see trx with id >= 36F, sees < 36F
|
这是一个最多见的缘由,一个14天前建立的至关老的事务。这个状态是活动的,这意味着 InnoDB 已经建立了一个数据的快照,因此须要在撤销日志中维护旧页面,以保障数据库的一致性视图,直到事务开始。若是你的数据库有大量的写入任务,那就意味着存储了大量的撤销页。sql
若是你找不到任何长时间运行的事务,你也能够监控INNODB STATUS 中的其余的变量,“History list length(历史记录列表长度)”展现了一些等待清除操做。这种状况下问题常常发生,由于清除线程(或者老版本的主线程)不能像这些记录进来的速度同样快地处理撤销。数据库
很不幸,MySQL 不提供查看什么被存储到 ibdata1 共享表空间的信息,可是有两个工具将会颇有帮助。第一个是马克·卡拉汉制做的一个修改版 innochecksum ,它发布在这个漏洞报告里。ruby
它至关易于使用:服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# ./innochecksum /var/lib/mysql/ibdata1
0 bad checksum
13 FIL_PAGE_INDEX
19272 FIL_PAGE_UNDO_LOG
230 FIL_PAGE_INODE
1 FIL_PAGE_IBUF_FREE_LIST
892 FIL_PAGE_TYPE_ALLOCATED
2 FIL_PAGE_IBUF_BITMAP
195 FIL_PAGE_TYPE_SYS
1 FIL_PAGE_TYPE_TRX_SYS
1 FIL_PAGE_TYPE_FSP_HDR
1 FIL_PAGE_TYPE_XDES
0 FIL_PAGE_TYPE_BLOB
0 FIL_PAGE_TYPE_ZBLOB
0 other
3 max index_id
|
所有的 20608 中有 19272 个撤销日志页。这占用了表空间的 93%。
第二个检查表空间内容的方式是杰里米·科尔制做的 InnoDB Ruby 工具。它是个检查 InnoDB 的内部结构的更先进的工具。例如咱们可使用 space-summary 参数来获得每一个页面及其数据类型的列表。咱们可使用标准的 Unix 工具来统计撤销日志页的数量:
1
2
|
# innodb_space -f /var/lib/mysql/ibdata1 space-summary | grep UNDO_LOG | wc -l
19272
|
尽管这种特殊的状况下,innochedcksum 更快更容易使用,可是我推荐你使用杰里米的工具去了解更多的 InnoDB 内部的数据分布及其内部结构。
好,如今咱们知道问题所在了。下一个问题:
这个问题的答案很简单。若是你还能提交语句,就作吧。若是不能的话,你必需要杀掉线程开始回滚过程。那将中止 ibdata1 的增加,可是很显然,你的软件会出现漏洞,有些人会遇到错误。如今你知道如何去鉴定问题所在,你须要使用你本身的调试工具或普通的查询日志来找出谁或者什 么引发的问题。
若是问题发生在清除线程,解决方法一般是升级到新版本,新版中使用一个独立的清除线程替代主线程。更多信息查看该文档
没有,目前尚未一个容易而且快速的方法。InnoDB 表空间从不收缩...参见10 年之久的漏洞报告,最新更新自詹姆斯·戴(谢谢):
当你删除一些行,这个页被标为已删除稍后重用,可是这个空间从不会被回收。惟一的方法是使用新的 ibdata1 启动数据库。要作这个你应该须要使用 mysqldump 作一个逻辑全备份,而后中止 MySQL 并删除全部数据库、ib_logfile*、ibdata1* 文件。当你再启动 MySQL 的时候将会建立一个新的共享表空间。而后恢复逻辑备份。
当 ibdata1 文件增加太快,一般是 MySQL 里长时间运行的被遗忘的事务引发的。尝试去解决问题越快越好(提交或者杀死事务),由于不通过痛苦缓慢的 mysqldump 过程,你就不能回收浪费的磁盘空间。
也是很是推荐监控数据库以免这些问题。咱们的 MySQL 监控插件包括一个 Nagios 脚本,若是发现了一个太老的运行事务它能够提醒你。