• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

MySQL InnoDB历史与架构

MySQL InnoDB 彭东稳 8年前 (2016-06-19) 21504次浏览 已收录 0个评论

一、InnoDB存储引擎

InnoDB是事务安全的MySQL存储引擎,设计上采用了类似于Oracle数据库的架构。通常来说,InnoDB存储引擎时OLTP应用中核心表的首选存储引擎。同样,也正是因为InnoDB的存在,才使MySQL数据库变得更有魅力。目前InnoDB属于MySQL默认存储引擎,并且在MySQL 8.0开始,包括元数据表也都是使用InnoDB存储引擎,之前是一直使用MyISAM存储引擎。

InnoDB存储引擎的创始人Heikki Tuuri1964年出生于芬兰赫尔辛基,与著名的Linux创始人Linus同时芬兰赫尔辛基大学校友,同时MySQL创始人Monty也是芬兰人,很传奇。他在1995年成立Innobase Oy公司并担任CEO。InnoDB最初就由Innobase Oy公司开发,后来被包括在MySQL所有的二进制发行版本中,也是MySQL 5.5.8开始默认的存储引擎。该存储引擎是一个支持ACID事务,行锁设计,支持MVCC功能,提供类似于Oracle风格的一致性非锁定读,支持外键,被设计用来最有效地利用内存和CPU。并且实现了SQL标准的4种隔离级别,其默认级别是REPEATABLE READ。并通过一种被称为netxt-key locking的策略来避免幻读。

其实从时间点上来看,InnoDB存储引擎比MySQL(1996年发布1.0版本)出现的还要早一些,起初InnoDB本身就是作为一个独立数据库而开发的,所以它很多功能是比较完整的。后来在2000年MySQL发布了2.0版本,其默认存储引擎就是ISAM(MyISAM的前身,在MySQL 3.23版本被MyISAM替换掉);这期间Innobase Oy公司其实是想把InnoDB给卖掉的,但是由于没人买就一直搁置着。由于MySQL发布2.0后在当时影响还是挺大的,并且由于MySQL是一个插件式数据库,就引起了Innobase Oy公司的注意,后来InnoDB创始人就找MySQL谈,希望MySQL把InnoDB当做一个存储引擎合并到MySQL中,很快双方达成协议,2001年InnoDB就被当做第三方存储引擎集成到MySQL数据库中去了。虽然集成到MySQL了,但是当时MySQL还是主推自家的MyISAM存储引擎,一个不支持事务,表级锁的存储引擎;所以当时如果你创建表时不指定InnoDB为表存储引擎时,默认就是使用MyISAM。好在MySQL 5.5.8版本开始就把InnoDB作为默认存储,所以用户就不需要创建表时还指定InnoDB成表存储引擎,为什么不需要呢?这主要是因为Oracle公司再2006年做了一件前瞻性的决定。

在2006年,Oracle公司收购了Innobase Oy公司,拥有InnoDB存储引擎。据说主要是因为在一次数据库大会上,InnoDB展示了一个表压缩功能,这在当时是很了不起的技术;一个开源的,支持事务、行锁、压缩、MVCC功能的存储引擎真正让Oracle公司感受到了威胁。这也导致了MySQL在很长一段时间内(2006-2010)InnoDB的版本没有任何发展,这几年MySQL也过的不是很好。最终在2008年被SUN公司收购,最后SUN被Oracle收购,自然MySQL也就到了Oracle手里。现在Oracle拥有MySQL数据库及InnoDB存储引擎,从Oracle收购MySQL,推出5.6、5.7、8.0几个大版本,做了大量的优化和功能,并且在8.0大量重构了InnoDB存储引擎,性能大幅度提升。可以说目前能大量重构InnoDB存储引擎的人估计也有Oracle官方团队可以了,包括InnoDB创始人目前也在Oracle公司,如果不出现MySQL被闭源的情况,那么Oracle官方MySQL可以说是前途一片大好。相比MariaDB及Percona来说,由于拥有InnoDB和可重构能力,只要Oracle肯去发展MySQL,那么生产使用基本可以不用考虑其他版本MySQL了。MariaDB就是MySQL被Oracle收购后,其创始人Monty fork MySQL又做出来的一个分支,但其还是使用InnoDB存储引擎;除非MariaDB能够有一款跟InnoDB相匹敌的存储引擎,可能会有意想不到的发展,不然就只能在MySQL层做一些复制及优化器的工作了。另外,目前InnoDB存储引擎的开发团队中,有来自中国科技大学的Calvin Sun,直到现在这个开发团队中有好几位中国人了。

InnoDB存储引擎已经跟随着MySQL进入到了很多大型网站中使用,如YahooFacebook、淘宝等。从MySQL的官方手册还能得知,著名的Internet新闻站点slashdot.org运行在InnoDB上。还有一些其它站点在InnoDB上处理平均每秒800次插入/更新的操作。这些都证明了InnoDB是一个高性能、高可用、高可扩展的存储引擎。

二、InnoDB体系架构

了解完MySQL的体系结构后,现在再看看InnoDB存储引擎的体系架构。下图简单显示了InnoDB的存储引擎体系结构,InnoDB有多个内存块,你可以认为这些内存块组成了一个大的内存池。

  • Innodb内存对象

InnoDB存储引擎内存有多个内存块组成,分别是缓冲池重做日志缓冲池以及额外的内存池。分别由变量innodb_buffer_pool_sizeinnodb_log_buffer_sizeinnodb_additional_mem_pool_size的大小决定(调优的参数)。你可以认为这些内存块组成了一个大的内存池,负责如下工作:

1. 维护所有进程/线程需要访问的多个内部数据结构。

2. 缓存磁盘上的数据,方便快速地读取,并且在对磁盘文件的数据进行修改之前在这里缓存。

3. 重做日志(redo log)缓冲,等等。

其中缓冲池是占最大块内存的部分,InnoDB将表的索引和数据进行缓存。缓冲池允许从内存直接处理频繁使用的数据,这加快了处理速度。在专用数据库服务器上,通常将多达80%的物理内存分配给InnoDB缓冲池。因为InnoDB的存储引擎的工作方式总是将数据库文件按页读取到缓冲池,每个页16k默认(innodb_page_size=16k),在MySQL 5.7中增加了32KB和64KB页面大小的支持,之前版本是不允许大于16k的;但你只能在初始化MySQL实例之前进行配置,一旦设置了一个实例的页面大小,就不能改变它,具体看innodb_page_size参数。然后按最近最少使用(LRU)算法来保留在缓冲池中的缓存数据。如果数据库文件需要修改,总是首先修改在缓存池中的页(发生修改后,该也即为脏也),然后再按照一定的频率将缓冲池的脏也刷新到文件中。可以通过show engine innodb status来查看innodb_buffer_pool的具体使用情况(默认是8个缓冲池实例),如下:

Buffer pool size中可以看到内存池的使用情况,Buffer pool size表明了一共有多少个缓冲帧(buffer frame),每个缓冲帧为16K,所以这里一共分配了63336*16/1024=1G内存的缓冲池。Free buffers表示当前空闲的缓冲帧,Database pages表示已经使用的缓冲帧,Old database pages表示存放不经常修改的数据页(一般占用内存的1/3),Modified db pages表示脏页的数量,这些数据能分析当前数据库的压力值。

根据上图具体来看:

缓冲池(buffer pool):缓存的数据类型有索引页(index pages)、数据页(data pages)、undo页(undo pages)、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息(lock info)、数据字典信息(data dictionary)等。

日志缓冲(log buffer)将重做日志(事务日志)信息先放入这个缓冲区,然后按一定频率将其刷新到重做日志文件。该值一般不需要设置为很大,默认情况下每一秒钟就会将重做日志缓冲刷新到日志文件,因为我们只需要保证每秒产生的事务量在这个缓冲大小之内即可。

额外的内存(additional mem pool):对于管理员来说也是十分重要的,在InnoDB中,对内存的管理是通过一种称为堆(heap)内存的方式进行。在对一些数据结构本身分配内存时,需要从额外的内存池中申请,当该区域的内存不够时,会从缓冲池中申请。Innodb实例会申请缓冲池的空间,但是每个缓冲池中的帧缓冲还有对应的缓冲控制对象,而且这些对象记录了诸如LRU、锁、等待等方面的信息,而这个对象的内存需要从额外内存池中申请。因此当你申请了很大的InnoDB缓冲池时,这个值也应该相应增加。

  • InnoDB后台线程

后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。此外,将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常情况下InnoDB能恢复到正常运行的状态。

默认情况下,InnoDB存储引擎的后台线程有7个:4IO threadinsertlogreadwrite),1master thread1个锁监控线程,1个错误监控线程。其中master thread线程几乎完成了InnoDB存储引擎所有的功能。(后面会详细介绍master thread

可以使用show engine innodb status查看InnoDB的状态信息,大概包括事务信息、缓冲池信息、行操作信息以及线程信息等。如下摘取了线程信息:

可以看到其中4IO线程分别是上图中的insert buffer threadlog threadread threadwrite thread。而read thread and write thread线程是由这两个变量innodb_read_io_threadsinnodb_write_io_threads来控制,默认各自开启4个线程。然后加起来也就出现上面我们看到的10个线程了。

InnoDB存储引擎的主要工作都是在一个单独的后台线程master thread中完成的,master thread的优先级也最高。 

三、InnoDB关闭与启动

InnoDB存储引擎现在是MySQL数据库的默认存储引擎,所以InnoDB存储引擎的启动和关闭更准确地是指在MySQL实例的启动过程中对InnoDB表存储引擎的处理过程。

在关闭时,参数innoDB_fast_shutdown影响着表的存储引擎为InnoDB的行为。该参数可取值0120表示当MySQL关闭时,InnoDB需要完成所有的full purgemerge insert buffer操作,这会需要一些时间,有时甚至需要几个小时来完成。如果在做InnoDB plugin升级,通常需要将这个参数调为0,然后再关闭数据库。1是该参数的默认值,表示不需要完成上述的full purgemerge insert buffer操作,但是在缓冲池中的数据脏页写回磁盘,而是将日志都写入日志文件。这样不会有任何事物会丢失,但是MySQL数据库下次启动时,会执行恢复操作。

当正常关闭MySQL数据库时,下一次启动应该会很正常。但是,如果没有正常地关闭数据库,如用kill命令关闭数据库,在MySQL数据库运行过程中重启了服务器,或者在关闭数据库时将参数innodb_fast_shutdown设为了2MySQL数据库下次启动时都会对InnoDB存储引擎的表执行恢复操作。

而参数innodb_force_recovery影响了整个InnoDB存储引擎的恢复状况。该值默认为0,表示当需要恢复时执行所有的恢复操作。当不能进行有效恢复时,如数据页发生了corruption时,MySQL数据库可能会宕机,并把错误写入错误日志中。如果在某些情况下,我们可能并不需要执行完整的恢复操作,我们自己知道如何进行恢复。比如正在对一个表执行alter table操作,这时意外发生了,数据库重启时会对InnoDB表执行回滚操作。对于一个大表,这需要很长时间,甚至可能几个小时。这时我们可以自行进行恢复,例如可以把表删除,从备份中重新将数据导入表中,这些操作的速度可能要远远快于回滚操作。

innodb_force_recovery还可以设置6个非零值:1-6。大的数字包含了前面所有小数字的影响,具体情况如下。

1:忽略检查到的corruption页。

2:阻止主线程的运行,如主线程需要执行full purge操作,会导致crash

3:不执行事务回滚操作。

4:不执行插入缓冲的合并操作。

5:不查看撤销日志(undo log),innodb存储引擎会将未提交的事务视为已提交。

6:不执行前滚操作。

需要注意的是,当设置参数innodb_force_recovery大于0后,可以对表进行selectcreatedrop操作,但insertupdate或者delete这类操作时不允许的。

四、InnoDB版本信息

InnoDB存储引擎从MySQL5.1开始就采用了插件式方式存在于MySQL中,而现在所有的存储引擎都是真正的插件式了。这样设计的好处是,如果发现一个InnoDB存储引擎的BUG,你能做的就是等待MySQL新版本的发布,InnoDB公司本身对此只能通过补丁的形式来解决,你还需要重新编译一次MySQL才行。现在,你可以得到一个新版本的InnoDB,用来替代有BUG的版本。对于新版本的InnoDB你可以把它看着是一个新版本的InnoDB Plugin存储引擎,因为它还带来了一系列新的特性,比如快速索引重建、更好的多核性能、新的页结构、页压缩功能等等。

另外MySQL中查看innodb版本的方法

InnoDBMySQL5.5开始的版本变化:

MySQL 5.5:

直到MySQL 5.6.3innodb版本为1.2.3,还可以使用上述变量查看。但是从MySQL5.6.11之后InnoDB停止单独版本编号,变量version_innodb的值变成变量version的值,也就是说等同于MySQL版本号,如下:

下面是官方摘取的Innodb版本变更信息:The innodb version number. Staring in 5.6.11the separate numbering for innodb is discontinued and this value is the same for the version variable.

<参考>

InnoDB存储引擎

https://yq.aliyun.com/articles/583754?spm=a2c4e.11155435.0.0.15f0135eEUSM1J


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (3)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!