MySQL问答系列之如何避免ibdata1文件大小暴涨

0、导读

ibdata1文件是什么?

ibdata1是一个用来构建innodb系统表空间的文件,这个文件包含了innodb表的元数据、撤销记录、修改buffer和双写buffer。如果file-per-table选项打开的话,该文件则不一定包含所有表的数据。当innodb_file_per_table选项打开的话,新创建表的数据和索引则不会存在系统表空间中,而是存放在各自表的.ibd文件中.

显然这个文件会越来越大,innodb_autoextend_increment选项则指定了该文件每次自动增长的步进,默认是8M.

是什么原因导致ibdata1文件会越来越大?

ibdata1存放数据,索引和缓存等,是MYSQL的最主要的数据。所以随着数据库越来越大,表也会越大,这个无法避免的。如果时间长了,越来越大,我们在处理日志和空间的时候就不是那么方便了,就不知从何入手了。接下来我们就要处理下这样的情况,分库存储数据。

遇到InnoDB的共享表空间文件ibdata1文件大小暴增时,应该如何处理?

1、问题背景

用MySQL/InnoDB的童鞋可能也会有过烦恼,不知道为什么原因,ibdata1文件莫名其妙的增大,不知道该如何让它缩回去,就跟30岁之后男人的肚腩一样,汗啊,可喜可贺的是我的肚腩还没长出来,hoho~

正式开始之前,我们要先知道ibdata1文件是干什么用的。

ibdata1文件是InnoDB存储引擎的共享表空间文件,该文件中主要存储着下面这些数据:

  • data dictionary
  • double write buffer
  • insert buffer/change buffer
  • rollback segments
  • undo space
  • Foreign key constraint system tables

另外,当选项 innodb_file_per_table = 0 时,在ibdata1文件中还需要存储 InnoDB 表数据&索引。ibdata1文件从5.6.7版本开始,默认大小是12MB,而在这之前默认大小是10MB,其相关选项是 innodb_data_file_path,比如我一般是这么设置的:

innodb_data_file_path = ibdata1:1G:autoextend

当然了,无论是否启用了 innodb_file_per_table = 1,ibdata1文件都必须存在,因为它必须存储上述 InnoDB 引擎所依赖&必须的数据,尤其是上面加粗标识的 rollback segments 和 undo space,它俩是引起 ibdata1 文件大小增加的最大原因,我们下面会详细说。

2、原因分析

我们知道,InnoDB是支持MVCC的,它和ORACLE类似,采用 undo log、redo log来实现MVCC特性的。在事务中对一行数据进行修改时,InnoDB 会把这行数据的旧版本数据存储一份在undo log中,如果这时候有另一个事务又要修改这行数据,就又会把该事物最新可见的数据版本存储一份在undo log中,以此类推,如果该数据当前有N个事务要对其进行修改,就需要存储N份历史版本(和ORACLE略有不同的是,InnoDB的undo log不完全是物理block,主要是逻辑日志,这个可以查看 InnoDB 源码或其他相关资料)。这些 undo log 需要等待该事务结束后,并再次根据事务隔离级别所决定的对其他事务而言的可见性进行判断,确认是否可以将这些 undo log 删除掉,这个工作称为 purge(purge 工作不仅仅是删除过期不用的 undo log,还有其他,以后有机会再说)。

那么问题来了,如果当前有个事务中需要读取到大量数据的历史版本,而该事务因为某些原因无法今早提交或回滚,而该事务发起之后又有大量事务需要对这些数据进行修改,这些新事务产生的 undo log 就一直无法被删除掉,形成了堆积,这就是导致 ibdata1 文件大小增大最主要的原因之一。这种情况最经典的场景就是大量数据备份,因此我们建议把备份工作放在专用的 slave server 上,不要放在 master server 上。

另一种情况是,InnoDB的 purge 工作因为本次 file i/o 性能是在太差或其他的原因,一直无法及时把可以删除的 undo log 进行purge 从而形成堆积,这是导致 ibdata1 文件大小增大另一个最主要的原因。这种场景发生在服务器硬件配置比较弱,没有及时跟上业务发展而升级的情况。

比较少见的一种是在早期运行在32位系统的MySQL版本中存在bug,当发现待 purge 的 undo log 总量超过某个值时,purge 线程直接放弃抵抗,再也不进行 purge 了,这个问题在我们早期使用32位MySQL 5.0版本时遇到的比较多,我们曾经遇到这个文件涨到100多G的情况。后来我们费了很大功夫把这些实例都迁移到64位系统下,终于解决了这个问题。

最后一个是,选项 innodb_data_file_path 值一开始就没调整或者设置很小,这就必不可免导致 ibdata1 文件增大了。Percona官方提供的 my.cnf 参考文件中也一直没把这个值加大,让我百思不得其解,难道是为了像那个经常被我吐槽的xx那样,故意留个暗门,好方便后续帮客户进行优化吗?(我心理太阴暗了,不好不好~~)

稍微总结下,导致ibdata1文件大小暴涨的原因有下面几个:

  • 有大量并发事务,产生大量的undo log;
  • 有旧事务长时间未提交,产生大量旧undo log;
  • file i/o性能差,purge进度慢;
  • 初始化设置太小不够用;
  • 32-bit系统下有bug。

稍微题外话补充下,另一个热门数据库 PostgreSQL 的做法是把各个历史版本的数据 和 原数据表空间 存储在一起,所以不存在本案例的问题,也因此 PostgreSQL 的事务回滚会非常快,并且还需要定期做 vaccum 工作(具体可参见PostgreSQL的MVCC实现机制,我可能说的不是完全正确哈)

3、解决方法建议

看到上面的这些问题原因描述,有些同学可能觉得这个好办啊,对 ibdata1 文件大小进行收缩,回收表空间不就结了吗。悲剧的是,截止目前,InnoDB 还没有办法对 ibdata1 文件表空间进行回收/收缩,一旦 ibdata1 文件的肚子被搞大了,只能把数据先备份后恢复再次重新初始化实例才能恢复原先的大小,或者把依次把各个独立表空间文件备份恢复到一个新实例中,除此外,没什么更好的办法了。

当然了,这个问题也并不是不能防范,根据上面提到的原因,相应的建议对策是:

  • 升级到5.6及以上(64-bit),采用独立undo表空间,5.6版本开始就支持独立的undo表空间了,再也不用担心会把 ibdata1 文件搞大;
  • 初始化设置时,把 ibdata1 文件至少设置为1GB以上;
  • 增加purge线程数,比如设置 innodb_purge_threads = 8
  • 提高file i/o能力,该上SSD的赶紧上;
  • 事务及时提交,不要积压;
  • 默认打开autocommit = 1,避免忘了某个事务长时间未提交;
  • 检查开发框架,确认是否设置了 autocommit=0,记得在事务结束后都有显式提交或回滚。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • mysql 误删除ibdata1之后的恢复方法

    mysql 误删除ibdata1之后如何恢复 如果误删除了在线服务器中mysql innodb相关的数据文件ibdata1以及日志文件 ib_logfile*,应该怎样恢复呢? 这时候应该一身冷汗了吧?==================================先抽根烟,冷静一下.==================================再观察一下网站,发现一切都很正常,数据的读取与写入操作都完全正常.这是怎么个情况? 其实,mysqld在运行状态中,会保持这些文件为打开状态,

  • MySQL的InnoDB扩容及ibdata1文件瘦身方案完全解析

    mysql的innodb扩容 为了添加一个数据文件到表空间中,首先要关闭 MySQL 数据库,编辑 my.cnf 文件,确认innodb ibdata文件的实际情况和my.cnf的配置是否一致,这里有两种情况: 1.my.cnf的配置 innodb_data_file_path=ibdata1:10G;ibdata2:10G:autoextend 如果当前数据库正在使用ibdata1,或者使用ibdata2,但ibdata2没有超过10G,则对my.cnf配置直接改成: innodb_data_

  • 完美解决mysql启动后随即关闭的问题(ibdata1文件损坏导致)

    机房一台服务器上的mysql运行一段时间了,突然出现了一个很奇怪的现象:重启后无法恢复了!准确情况是:启动mysql后随即就又关闭了. 查看mysql错误日志如下: 160920 22:41:41 mysqld_safe Starting mysqld daemon with databases from /home/MysqlData/ 2016-09-20 22:41:41 0 [Note] /Data/app/mysql5.6.25/bin/mysqld (mysqld 5.6.25-lo

  • MySQL问答系列之如何避免ibdata1文件大小暴涨

    0.导读 ibdata1文件是什么? ibdata1是一个用来构建innodb系统表空间的文件,这个文件包含了innodb表的元数据.撤销记录.修改buffer和双写buffer.如果file-per-table选项打开的话,该文件则不一定包含所有表的数据.当innodb_file_per_table选项打开的话,新创建表的数据和索引则不会存在系统表空间中,而是存放在各自表的.ibd文件中. 显然这个文件会越来越大,innodb_autoextend_increment选项则指定了该文件每次自动

  • MySQL问答系列之什么情况下会用到临时表

    临时表介绍 什么是临时表:MySQL用于存储一些中间结果集的表,临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间.为什么会产生临时表:一般是由于复杂的SQL导致临时表被大量创建 临时表分为两种,一种是内存临时表,一种是磁盘临时表.内存临时表采用的是memory存储引擎,磁盘临时表采用的是myisam存储引擎(磁盘临时表也可以使用innodb存储引擎,通过internal_tmp_disk_storage_engine参数来控制使用哪种存储引擎,从mysql5.7.6之后

  • Mysql精粹系列(精粹)

    关于Mysql整理的需要记忆和熟练掌握的内容 1. /* 查看操作 */ ------------------------------------------------------------------------------------------------------- 1. /* 查看操作 */ SHOW PROCESSLIST -- 显示哪些线程正在运行 SHOW VARIABLES -- 查看变量 2. /* 数据库操作 */ --------------------------

  • 面试中老生常谈的MySQL问答集锦夯实基础

    目录 1.数据库架构 1.1.MySQL的基础架构图 1.2.一条SQL查询语句在MySQL中如何执行的? 2.SQL优化 2.1.日常工作中你是怎么优化SQL的? 2.1.1.优化表结构 2.1.2.优化查询 2.1.3.索引优化 2.2.怎么看执行计划(explain),如何理解其中各个字段的含义? 2.3.关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过? 3.索引 3.1.聚集索引与非聚集索引的区别 3.2.为什么要用B+树,为什么不用普通二叉树? 3.2.1.为什

  • MySQL OOM 系列一 Linux内存分配

    RDS(网易云关系数据库服务)上线已经有一段时间,陆续不断有产品迁入到了RDS中,在线上运维的过程中,也遇到了一些曾经没有考虑到,或者考虑的不全的东西.后续有时间可以分享给大家. 今天想提到的是线上一个4G的RDS实例,发生了OOM(out of memory)的问题,MySQL进程被直接Kill掉了.在解释这个问题的时候,我们首先需要从Linux系统内存分配策略讲起.     一般写C语言程序,我们习惯使用malloc动态的申请内存空间(Java由JVM负责内存管理),malloc函数会向操作

  • mysql优化系列 DELETE子查询改写优化

    1.问题描述 朋友遇到一个怪事,一个用子查询的DELETE,执行效率非常低.把DELETE改成SELECT后执行起来却很快,百思不得其解. 下面就是这个用了子查询的DELETE了: [yejr@imysql.com]mydb > EXPLAIN delete from trade_info where id in ( select id from ( select a.id from trade_info a, order_info b, user c where b.buyer = c.id

  • MySQL OOM 系列三 摆脱MySQL被Kill的厄运

    前面两章,我们分析了Linux内存分配的策略以及Linux通过使用 OOM_Killer的机制解决了"超售"引起的风险,MySQL同其他的应用程序一样,在操作系统允许的范围内也是可以超售的,一般人理解,Innodb_buffer_pool必须小于实际物理内存,否则MySQL会启动失败.其实这是一个误区,这个不是MySQL层控制的,这个是操作系统(OS)层控制的,就是前面提到的/proc/sys/overcommit_memory控制OS是否允许"超售".如果允许&q

  • MySQL 5.7临时表空间如何玩才能不掉坑里详解

    导读 MySQL 5.7的目标是成为发布以来最安全的MySQL服务器,其在SSL/TLS和全面安全开发方面有一些重要的改变. MySQL 5.7起支持独立临时表空间,但个别时候也可能会踩坑的. MySQL 5.7起,开始采用独立的临时表空间(和独立的undo表空间不是一回事哟),命名ibtmp1文件,初始化12M,且默认无上限. 选项 innodb_temp_data_file_path 可配置临时表空间相关参数. innodb_temp_data_file_path = ibtmp1:12M:

  • 详解MySQL中InnoDB的存储文件

    从物理意义上来讲,InnoDB表由共享表空间文件(ibdata1).独占表空间文件(ibd).表结构文件(.frm).以及日志文件(redo文件等)组成. 1.表结构文件 在MYSQL中建立任何一张数据表,在其数据目录对应的数据库目录下都有对应表的.frm文件,.frm文件是用来保存每个数据表的元数据(meta)信息,包括表结构的定义等,.frm文件跟数据库存储引擎无关,也就是任何存储引擎的数据表都必须有.frm文件,命名方式为数据表名.frm,如user.frm. .frm文件可以用来在数据库

随机推荐