Mysql的BufferPool机制
缓存Pool机制
缓存,很多人都不陌生了,几乎随处可见,Mysql也不例外,同样有缓存。通过其实现的Buffer Pool加快读和写的速度。
类似于操作系统缓存的缓存行Cache line,Mysql是以页为单位进行缓存的。
BufferPool是由多个BufferPool 实例组成的,每个实例是由多个chunk组成的。一个chunk就是一片连续的内存空间。示意图:
看上面实例中,每个buffer pool中都有三个链表,这也是最重要的三个链表:空闲列表,脏页链表,LRU链表。
空闲链表存储的所有空闲的页,这个就像JVM在内存分配时使用的空闲内存列表一样。
脏页链表存储的是已经被修改或删除,但还未被刷到磁盘上的数据。
LRU链表主要用来进行内存淘汰。这个后面会具体说。
Mysql读操作过程:
1、首先从缓存中获取对应数据,如果命中,直接取出,返回。如果没有命中,往下走;
2、从磁盘中加载数据到内存;如果Free list空闲列表有足够数据页则使用,如果没有就需要走第三步;
3、LRU执行缓存数据淘汰。
加速写:
首先会写到缓冲区的redo buffer中,不直接同步刷盘。刷磁盘同步操作由其他后台线程处理。
Mysql的内存淘汰
从名称LRU list就可以看出,它不是简单的LRU策略。因为其要保证热点数据不会被淘汰(缓冲区污染),此外要解决预读失效的问题。它将整个LRU 链表分成了新生代和老年代。
新生代和老年代首尾相连,老年代是可能被淘汰的数据,数据是排序的,链表尾部先被淘汰。新生代和老年代的比例可以人为配置。
当有新数据进入时,首先会插入到老年代的头部,且淘汰尾部。当是已在缓存中的数据,直接将页放到新生代的头部。
Mysql解决缓冲区污染的方法是当新生代中的数据被访问时,不会立即将其加入到新生代中,它设置了一个停留时间窗口T,只有被访问且在停留时间大于T的才会被访问。
还有一点是预读失效。Mysql预读就是预先读取一些可能将来被访问的数据到缓存,其利用的是我们经常说得局部性原理,即时间局部性和空间局部性。但可能也有预读失败的,即提前缓存的数据永远不会访问到。Mysql用新生代和老生代,使得刚进来的数据不会直接插入到链表头部,而是只插入到老生代的头部。
参考资料:
[玩转MySQL之十]InnoDB Buffer Pool详解
微信分享/微信扫码阅读