为什么别人能用好 MySQL?万字详解其复杂原理

来源:简书-七把刀
https://www.jianshu.com/p/d4cc0ea9d097
MySQL InnoDB 引擎现在广为使用,它提供了事务,行锁,日志等一系列特性,本文分析下 InnoDB 的内部实现机制,MySQL 版本为 5.7.24,操作系统为 Debian 9 。
MySQL InnoDB 的实现非常复杂,本文只是总结了一些皮毛,希望以后能够研究的更加深入些 。
1、InnoDB 架构
为什么别人能用好 MySQL?万字详解其复杂原理

文章插图
 
Innodb 架构图
InnoDB 的架构分为两块:内存中的结构和磁盘上的结构 。InnoDB 使用日志先行策略,将数据修改先在内存中完成,并且将事务记录成重做日志(Redo Log),转换为顺序IO高效的提交事务 。
这里日志先行,说的是日志记录到数据库以后,对应的事务就可以返回给用户,表示事务完成 。但是实际上,这个数据可能还只在内存中修改完,并没有刷到磁盘上去 。内存是易失的,如果在数据落地前,机器挂了,那么这部分数据就丢失了 。
InnoDB 通过 redo 日志来保证数据的一致性 。如果保存所有的重做日志,显然可以在系统崩溃时根据日志重建数据 。
当然记录所有的重做日志不太现实,所以 InnoDB 引入了检查点机制 。即定期检查,保证检查点之前的日志都已经写到磁盘,则下次恢复只需要从检查点开始 。
2、InnoDB 内存中的结构内存中的结构主要包括 Buffer Pool,Change Buffer、Adaptive Hash Index以及 Log Buffer 四部分 。
如果从内存上来看,Change Buffer 和 Adaptive Hash Index 占用的内存都属于 Buffer Pool,Log Buffer占用的内存与 Buffer Pool独立 。
Buffer Pool缓冲池缓存的数据包括Page Cache、Change Buffer、Data Dictionary Cache等,通常 MySQL 服务器的 80% 的物理内存会分配给 Buffer Pool 。
基于效率考虑,InnoDB中数据管理的最小单位为页,默认每页大小为16KB,每页包含若干行数据 。
为了提高缓存管理效率,InnoDB的缓存池通过一个页链表实现,很少访问的页会通过缓存池的 LRU 算法淘汰出去 。
InnoDB 的缓冲池页链表分为两部分:New sublist(默认占5/8缓存池) 和 Old sublist(默认占3/8缓存池,可以通过 innodb_old_blocks_pct修改,默认值为 37),其中新读取的页会加入到 Old sublist的头部,而 Old sublist中的页如果被访问,则会移到 New sublist的头部 。
缓冲池的使用情况可以通过 show engine innodb status 命令查看 。其中一些主要信息如下:
----------------------BUFFER POOL AND MEMORY----------------------Total large memory allocated 137428992 # 分配给InnoDB缓存池的内存(字节)Dictionary memory allocated 102398  # 分配给InnoDB数据字典的内存(字节)Buffer pool size   8191 # 缓存池的页数目Free buffers       7893 # 缓存池空闲链表的页数目Database pages     298  # 缓存池LRU链表的页数目Modified db pages  0    # 修改过的页数目......Change Buffer通常来说,InnoDB辅助索引不同于聚集索引的顺序插入,如果每次修改二级索引都直接写入磁盘,则会有大量频繁的随机IO 。Change buffer 的主要目的是将对 非唯一 辅助索引页的操作缓存下来,以此减少辅助索引的随机IO,并达到操作合并的效果 。它会占用部分Buffer Pool 的内存空间 。
在 MySQL5.5 之前 Change Buffer其实叫 Insert Buffer,最初只支持 insert 操作的缓存,随着支持操作类型的增加,改名为 Change Buffer 。
如果辅助索引页已经在缓冲区了,则直接修改即可;如果不在,则先将修改保存到 Change Buffer 。Change Buffer的数据在对应辅助索引页读取到缓冲区时合并到真正的辅助索引页中 。Change Buffer 内部实现也是使用的 B+ 树 。
可以通过 innodb_change_buffering 配置是否缓存辅助索引页的修改,默认为 all,即缓存 insert/delete-mark/purge 操作(注:MySQL 删除数据通常分为两步,第一步是delete-mark,即只标记,而purge才是真正的删除数据) 。
为什么别人能用好 MySQL?万字详解其复杂原理

文章插图
 
查看Change Buffer 信息也可以通过 show engine innodb status 命令 。更多信息见
-------------------------------------INSERT BUFFER AND ADAPTIVE HASH INDEX-------------------------------------Ibuf: size 1, free list len 0, seg size 2, 0 mergesmerged operations: insert 0, delete mark 0, delete 0discarded operations: insert 0, delete mark 0, delete 0Hash table size 34673, node heap has 0 buffer(s)Hash table size 34673, node heap has 0 buffer(s)Hash table size 34673, node heap has 0 buffer(s)Hash table size 34673, node heap has 0 buffer(s)Hash table size 34673, node heap has 0 buffer(s)Hash table size 34673, node heap has 0 buffer(s)Hash table size 34673, node heap has 0 buffer(s)Hash table size 34673, node heap has 0 buffer(s)


推荐阅读