MySQL(五)——缓存

缓存

​ 当我们访问一条记录时,要把这个页的数据都加载到内存中并且缓存起来。在mysql启动时,就像操作系统申请了一篇连续的内存,缓冲池——buffer pool,默认128M。可以通过innodb_buffer_pool_size来修改。池中的缓存页默认也是16kb

​ 每一个缓存页会有对应的控制块,占用一块内存(约为808字节,5%),存放了控制信息(表空间编号、页号、缓存页的地址、链表节点信息、锁和LSN信息)

img

free链表

​ 用来管理哪些缓存页还没有被占用,也就是空闲的,会把每一个空闲缓存页对应的控制块加入到free链表中.每个节点占40字节,是单独申请的一块内存空间.每次加载了一个数据页后,就从free链表中取出一个空闲的缓存页,并把该缓存页对应的控制块的信息填上,然后从free链表中移除该控制块节点。

缓存页的哈希处理

​ 查找buffer pool中的缓存页通过表空间号+页号作为key,缓存页是对应的value。来组成一个哈希表

flush链表

​ 如果一个缓存页的数据被更新了,说明他是脏页了,会把这些脏页对应的控制块加入到flush链表中去

LRU链表

​ 如果缓存页已经用满了,如何删除掉不用的缓存页呢。通过最近最少使用算法来淘汰(同redis),所以需要维护一个LUR链表,当刚加载到缓存池中时,会放到链表的头部。每一次访问就把对应的控制块移动到头部,这样尾部的节点就是最近最少使用的缓存页了。

​ 问题:

  • 预读:可能判断会读,但其实没读

  • 全表扫描,会对缓冲池进行好几轮换血

    解决:

    • 把LRU链表按照比例分成冷热两块,默认冷链占37%,3/8左右。
    • 这样预读就会放在old链的头部
    • 全表扫描:首次加载的会被放到old区的头部。且在首次加载后的一定时间间隔内,再次访问改页的数据,不会把他放到young区(热链)默认1秒。
    • 只有在热链区域的1/4后面,才会被移动到LRU链表的头部,就可以降低调整的频率。

刷新脏页到磁盘

​ 后台有线程专门把脏页刷新到磁盘:

  • LRU链表的冷数据中刷新一部分页面到磁盘。从尾部开始如果发现脏页就刷新到磁盘
  • 从flush中刷新一部分到磁盘

多个buffer pool实例

​ 如果多线程且并发高的情况下,单一的pool会因为多线程加锁而影响处理速度,如果pool比较大的时候(大于1g,如果小于1g设置多个是没用的),会拆分成若干个小pool,单独申请内存空间,这样多线程并发访问时可以提高并发能力。5.7.5之后可以动态调整pool的大小,这时,重新申请,再把旧的拷过来太耗时,所以会把连续申请改为chunk为单位申请,所以一个pool是有若干个chunk组成。包含了若干缓存页的chunk。如果pool size变化的时候就通过chunk增减来完成。不需要重新申请再复制

你可能感兴趣的:(MySQL(五)——缓存)