赞
踩
关于InnoDB底层架构,网上有一张非常经典的图:
首先InnoDB从整体上分为两大块,一块是内存结构,一块是磁盘结构。
内存结构方面主要有“Buffer Pool”、“Log Buffer”、“Adaptive Hash Index”,其中“Buffer Pool”中还包含了一个“Change Buffer”要特别注意。
而磁盘结构则主要是各种表空间tablespace,以及Redo Log日志文件。
Redo Log很好理解,就是内存中的log buffer持久化到磁盘中的日志文件。
而这里的各种表空间,就有点多,主要包含5类表空间:“System Tablesapce”、“File-Per-Table Tablespaces”、“General Tablespaces”、“Undo Tablespaces”、“Temporary Tablespaces”。
以上是MySQL 5.7版本的,MySQL 8.0版本做了一些改动。
内存结构是没有变化的,还是保持原来的模样,而磁盘结构做了一定的调整。
首先是系统表空间System Tablesapce,做了简化,只保留Change Buffer的持久化内容,其他的东西都去掉了(System Tablesapce里面的东西会在下面介绍),或者从系统表空间中移出去了。
然后就是增加了一个“Doublewrite Buffer Files”,这个就是从系统表空间中移出来的东西(Doublewrite Buffer也会在下面介绍)。
以上是对InnoDB底层架构从宏观角度上的一个介绍,接下来我们一一对其中每个组件进行分析。
Buffer Pool是InnoDB自带的缓存,用于缓存由于SQL执行的增删改查而读取到内存中的数据页。下次再有查询需要读取相同的数据页时,就可以直接从缓存中读取。
首先我们要明白一点,MySQL是以页(16KB)为单位进行读取,也就是即使我们查询的是一行数据,MySQL也会读取一个页到内存中,也就是磁盘中该行记录所在的数据页,这是基于局部性原理的一个设计。
比如我们要查询id为1的一条记录,InnoDB就会查找到id为1的记录所在的数据页,把它加载到内存中,Buffer Pool就会把该数据页缓存起来,当我们下次再读取id为1的记录,或者与之相邻的同在一个数据页中的其他记录,就无需再从磁盘中把该数据页读到内存,而是直接在该页中查找并返回,这样就提升了查询性能。
Buffer Pool以链表的形式存放加载进来的数据页,Buffer Pool有三个链表:Free List,LRU List,Flush List。
Free List 是空闲链表,Buffer Pool中最开始只有Free List,而LRU List和Flush List都是空的。MySQL一启动,InnoDB就会向操作系统申请内存作为Buffer Pool的空间,然后将该内存空间分成固定大小16KB的一个一个的缓存页,存放在Free List中。
当执行SQL时,需要加载某个数据页到内存中,就会从Free List中拿出一个缓存页存放加载到内存中的数据,该数据页存放在LRU List中。LRU List 顾名思义,是使用了LRU算法的一个链表,当Free List中已经没有空闲的缓存页可以分配时,LRU List就会根据LRU算法把旧的缓存页淘汰出Buffer Pool,然后再把腾出的空间给最新加载进来的数据页使用。
如果某个被加载进Buffer Pool的页面被修改,它就会被挪到Flush List,此时它就变成一个脏页,等待被InnoDB刷到磁盘。
这里的LRU List有一点要注意,它使用的LRU算法不是经典的LRU算法,而是经过改进的LRU算法。如果按照经典的LRU算法,那么每个页被访问一次,就要把它放到头部,但如果这样的话,就会存在全表扫描时数据量过大导致冷数据把热点数据挤出的问题。
因此改进后的LRU算法把LRU链表分成两部分,一部分是Young区域,默认占LRU List大小的5/8,另一部分是Old区域的3/8。当内存不足需要淘汰一部分LRU List中的缓存页时,就会优先淘汰Old区域的缓存页。
当一个数据页首次被访问时,会被加载到LRU List的Old区,如果该缓存页最后一次被访问的时间距离首次被访问的时间超过了1秒,就会被挪到Young区,否则还是会继续呆在Old区。之所以这么设计,是因为每扫描一行记录,都算作是对该页的一次访问,在全表扫描的情况下,就会对一个数据页访问很多次,因此需要设置一个1秒的时间间隔,只有第一次与最后一次访问的时间间隔超过1秒,才移到Young区域中。
当我们向MySQL服务端提交一条update语句时,InnoDB就要对相应的数据页做修改。如果该数据页已缓存到了Buffer Pool,那InnoDB可以直接修改缓存页,然后把它移到Flush List,异步刷盘,再加上Redo Log的预写日志机制,即能保证更新不丢失,又能提升性能。但是如果要修改的数据页不在Buffer Pool中的话,是不是就要马上读到内存中呢?显然不是,如果这样做,那么InnoDB的写性能就会很低,因为从磁盘读取数据页是一个随机读的操作,磁盘的随机读性能是很低的,因此InnoDB就搞了个Change Buffer,用于缓存更新操作,它也是Buffer Pool的一部分。
InnoDB先把对没有加载到Buffer Pool中的数据页的修改(增删改)操作缓存到Change Buffer中,等到下次接收到读取该数据页的命令时,该数据页加载到Buffer Pool后,就把Change Buffer中缓存的对该数据页的修改操作应用到该缓存页中,这个操作叫merge操作。
缓存在Change Buffer中的更新操作也会写入到redo log中,因此不会发生更新丢失的情况。
Redo Log会缓存在内存中的Log Buffer中,Redo Log默认是每次提交事务时就刷盘,但是我们也可以配置为异步刷盘。
上面介绍的Buffer Pool会缓存从磁盘中加载到内存的数据页,下一次查询读取的数据如果位于相同的数据页时,由于Buffer Pool已经缓存了该数据页,因此无需再从磁盘中读取。那问题是?InnoDB怎么知道Buffer Pool中是否存在当前查询需要读取的数据页呢?
答案就是通过“Adaptive Hash Index”,“Adaptive Hash Index”意思是“自适应哈希索引”,是InnoDB自带的一个索引,默认开启,不可关闭。
Adaptive Hash Index 以表空间号加页号作为key,查找对应的数据页是否已经缓存在了Buffer Pool中,如果缓存命中,则直接返回。缓存不命中,再去磁盘中读取。
以上都是内存结构中的组件,下面我们对磁盘结构中的组件进行分析。
系统表空间分为四部分:“InnoDB Data Dictionary”、“Doublewrite Buffer”、“Change Buffer”、“Undo Logs”。
上面的四个部分,除了Doublewrite Buffer是没有介绍过的,其他一看就知道是干嘛的,下面介绍一下Doublewrite Buffer的作用。
因为InnoDB一页的大小是16KB,当InnoDB刷脏页到磁盘时,每刷一个脏页,等于是往磁盘写16KB的数据,InnoDB必须保证要么16KB全部刷写成功,要么就全部失败,不能刷到一半就GG,比如刷了8KB,然后MySQL挂了,那么这一个页就废了,前面8KB是刷脏页刷进来的数据,后面8KB是原来的数据。
因此,Doublewrite Buffer的作用就是保证脏页刷到磁盘时的“原子性”。InnoDB刷脏页时不直接刷到磁盘的数据页上,而是先刷到Doublewrite Buffer中。当脏页成功刷到Doublewrite Buffer之后,那么这个脏页就持久化到磁盘,即使MySQL挂了,重启也能取到这个脏页的数据。如果刷到Doublewrite Buffer成功,那么再写入到磁盘数据页中,否则就算是刷脏页失败,也能保证我们的数据页是正确的,只是该数据页是没更新数据之前的,此时可以通过redo log重做一遍,然后重写刷脏页即可。
我们看下刷脏页失败的两种情况:
第一种情况,MySQL重启后,可以通过redo log恢复出脏页,然后再重新刷一遍Doublewrite Buffer。
第二种情况,MySQL重启后,根据Doublewrite Buffer再写一次磁盘数据页就可以了。
Undo Tablespaces是Undo Log的表空间集合,InnoDB默认不会写入到Undo Tablespaces里面的表空间,而是默认写入到System Tablespace系统表空间的Undo Logs区域,只有当我们配置了写到Undo Log自己的独立表空间时,才会写入到Undo Tablespaces里面。
但是在MySQL8.0以上的版本,做了改进,从System Tablespace中移除了Undo Logs,默认存储到Undo Tablespaces中。
InnoDB中的redo log是重做日志,用于保障事务的持久性,当事务提交时,首先写入到内存结构中的Log Buffer区域,然后默认会立刻持久化到磁盘中,持久化到磁盘中时就会存储在磁盘结构中的Redo Log,磁盘结构中的Redo Log指的是磁盘中的redo log文件。
redo log文件的文件名一般是ib_logfile0、ib_logfile1这种固定的格式。并且redo log文件不是无限增长的,而是固定大小,固定文件个数的,当写到最后一个文件并且写满之后,就会回到第一个文件开头,覆盖式的写入,相当于是一个环状结构。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。