从零开始带你成为MySQL实战优化高手学习笔记(三)MySQL Buffer Pool的运行过程

在之前的文章《从零开始带你成为MySQL实战优化高手学习笔记(二) 关于buffer pool的相关知识》中,已经简单的了解了的一些buffer pool的东西:free链表用来记录哪些缓存页是空的,flush链表记录哪些是被修改过的。

这一小节,主要讲MySQL的buffer pool运行的整个过程。

目录

1、缓存页满了怎么办?

1.1、LRU淘汰算法

1.1.1、策略:

1.1.2、存在的问题:

1.2、基于冷热数据分离的思想设计LRU链表

1.2.1、策略

1.2.2、性能优化

1.3、冷数据的刷盘机制

1.4、总结

2、存在的问题

3、buffer pool需不需要加锁?


1、缓存页满了怎么办?

但是,free链表总会有空的时候,也就是说缓存页都满了,再没有空余缓存用来加载磁盘上的数据页?

这时候我们想,怎么办?是不是要把一部分缓存页淘汰掉,也就是清空,然后再加载新的数据页到缓存页。

如何淘汰?

 

1.1、LRU淘汰算法

 

1.1.1、策略:

MySQL使用了LRU淘汰算法,LRU也就是least recently use,最近最少使用。

策略就是使用的缓存页就加到LRU链表的头部,只要修改或者查询过就会移到链表头部,最后淘汰LRU尾部的。

 

1.1.2、存在的问题:

 1、MySQL有个预读机制:当从磁盘中加载一个数据页的时候,有可能会把相邻的数据页也一块加载到缓存页。

这会带来什么问题?

看上图,比如,空间大小就为4,原本ABC都是经常被访问的,现在要加入虚线那两个数据页,必须要淘汰一个,那肯定就淘汰C,就把常访问的淘汰了,留下了没有访问的相邻数据页。

 

那么在此就有必要了解一下MySQL的预读机制

①、通过参数innodb_read_ahead_threshold控制,默认是56。这个参数表示如果顺序访问了一个区里的多个数据页,这里的多个就是56,就会触发预读机制,把下一个区中所有的数据页都加载到缓存页里。

②、通过参数innodb_random_read_ahead控制,默认是off。这个参数表示如果缓存了一个区的13个连续数据页,就会触发预读机制,把这个区里的页全都加载到缓存页里。

2、全表扫描

如果是全表扫描,会把全表都加载到buffer pool中,有可能就把LRU链表中经常访问的都挤到后面去,就有可能被淘汰。

如何优化呐?


既然有经常访问的数据,又有不常访问的数据,是不是可以在LRU链表中分区啊,对这两块数据分别管理。

 

1.2、基于冷热数据分离的思想设计LRU链表

所有把LRU链表分为两部分,冷热比例由innodb_old_blocks_pct参数控制,默认是37,也就是说冷数据占比37%。

 

1.2.1、策略

第一次加载的数据页,直接放到冷数据区域的头部。

那什么时候放到热数据区域那?

通过参数innodb_old_block_time控制,默认1000,毫秒。这个参数表示,必须数据页加载到缓存页1000毫秒之后再次访问才加到热数据区域。

 

1.2.2、性能优化

位于热数据区域的数据,如果被访问了,应不应该立即加载热数据区域的头部?

无论链表方不方便,频繁的移动肯定是不希望的。MySQL规定,只有在热数据的后3/4部分的数据被访问了才会移动到链表头部。

 

1.3、冷数据的刷盘机制

之前的讨论都是说缓存满了才淘汰尾部数据刷入磁盘,实际上并不是非得等满了。后台有一个线程,运行一个定时任务,每隔一段时间就刷入磁盘然后清空这几个缓存页,并加到free链表中。

别忘了,刷入磁盘的不仅仅是冷数据区域,还有flush链表,等MySQL不是很忙的时候就会执行,然后从flush链表和LRU链表中移除。

 

1.4、总结

实际上就是不断的加载数据页到缓存页,然后不停的查询和修改缓存数据,free链表不停的减少,flush链表不停的增加,LRU链表不停的增加和移动。

另一边,后台线程不停的把LRU中的冷数据以及flush中的数据刷入磁盘,清空一部分缓存页。flush链表和LRU链表在减少,free链表在增多。

 

2、存在的问题

如果要加载数据到缓存页,但是没空间了,就需要把冷数据刷盘,然后再读如缓存页,这就是两次磁盘IO。如果一直遇到这种情况,性能肯定很差,这又该怎么办?

咱们想想出现这种情况的原因是啥?是不是空间太小了啊,所以终极解决办法就是加大buffer pool的空间,毕竟默认才128M。

3、buffer pool需不需要加锁?

以上的流程,咱们说的都是单线程。如果是同时有多个请求,MySQL肯定会使用多线程来访问buffer pool,情形就是下面这样:

那么,依据咱们的经验,必然需要加锁。加锁随之而来的就是性能问题,虽然buffer pool在内存中,速度挺快,但是毕竟加锁后一个一个来,万一需要从磁盘加载到内存中,这不是还有一次磁盘IO,必然会慢一点。

再依据咱们的经验,这时候是不是要开始分buffer pool了,原本一个,我设置成四个,四个独立,这不就变快了么。

 

可以通过两个参数控制

innodb_buffer_pool_size和innodb_buffer_pool_instances

总大小/数量就是单个buffer pool的大小。

那么,就形成了下面这种情况:

其实这种情况最终极的解决办法就是分布式数据库,比如阿里的OceanBase。

系列学习笔记:

从零开始带你成为MySQL实战优化高手学习笔记(一)

从零开始带你成为MySQL实战优化高手学习笔记(二) 关于buffer pool的相关知识

从零开始带你成为MySQL实战优化高手学习笔记(三)MySql byffer pool的运行过程

 

 

 

欢迎关注微信公众号,公众号的好处是可以持续保持联系。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值