10解决预读问题的改进的LRU算法
10.1 基于冷热数据分离思想的LRU链表
为了解决上述提到的问题,Mysql在设计LRU链表的时候,采用冷热数据分离的思想。
LRU链表会被拆分成两个部分:一部分是热数据,一部分是冷数据。
冷热数据比率由这个函数控制:
innodb_old_blocks_pct
这个函数默认值是37,也就是说,默认有37%的冷数据。
可以形象的认为,LRU链表的头指针指向热数据区域,LRU链表的尾指针指向冷数据区域。
10.2 实际的加载数据页的过程
数据页第一次被加载进缓存的时候,系统会把数据页存放在冷数据页区的第一个。
innodb_old_blocks_time
默认参数1000
这个参数代表,经过一定时间间隔后,如果这个数据页被访问了,则把这个数据页转移到热数据页区的第一个。
10.3 热数据页区的注意事项
因为热数据页区的缓存页是经常被访问的,所以自然如果经常性的移动这些页,就会造成性能的降低。
所以LRU链表的热数据区域的访问规则有过一定的优化:
只有在热数据区后3/4部分区域的缓存页被访问了,才会移动到LRU表头去。
11 LRU链表末尾刷入磁盘
11.1 定时
在后台有一个线程负责间隔一定时间,把LRU末尾的缓存页写回磁盘,并且加入Free链表之中,从flush链表中删除
11.2 别忘了flush
mysql在不怎么繁忙的时候,找个时间就会把flush链表中的缓存页都写回磁盘之中的。
所以这是一个动态的效果,一边不停地加载数据到缓存页中,不停地查询和修改缓存数据,然后free链表中的缓存页不停地在减少,flush链表中的缓存页不停地在增加。lru链表中的缓存页不停地在增加和移动。
后台线程不停地把lru链表的冷数据区域的缓存页以及flush链表的缓存页写回磁盘之中,然后flush链表和lru链表的缓存页在减少,free链表的缓存页在增加。
12 多线程并发访问BufferPool
12.1 加锁
显然,在多个线程并发的访问BufferPool的时候,必须要加上锁。
所以实际上,很多线程应该是串行的排着队的使用和访问BufferPool。
而且由于BufferPool是在内存之中,而且很多链表的操作都是指针,所以这种性能上的损失可以忽略不计。
但是,在牵涉到IO操作的时候,就会耗时稍微长一点。
12.2 多个BufferPool
一般来说,mysql默认的规则是,如果你给BufferPool分配的内存大小小于1GB,则最多只会给你一个BufferPool。
所以如果我们的内存空间很大, 我们可以设置多个BufferPool
[server]
innodb_buffer_pool_size = 8589934592 // 设置8G大小
innodb_buffer_pool_instance = 4 // 设置4个BufferPool
13 chunk对BufferPool进行动态调整
BufferPool实际上是由很多chunk组成的。每一个chunk的大小可以由下面的代码进行控制
innodb_buffer_pool_chunk_size
默认值128mb
13.1 实际情况
假设8G内存,就可以有4个BufferPool。
然后每个BufferPool由16个chunk组成。
4个BufferPool由4套不同链表(free,flush,lru)
每一个BufferPool中的chunk共享使用同一套链表
13.2 如何动态调整
如果我们现在的BufferPool的大小8GB,我想要增加到16GB,那么我只要重新申请若干个大小为128mb的chunk,然后把这些chunk动态的添加到BufferPool之间就可以了。
14 生产环境之中,如何基于机器配置来合理设置BufferPool
- BufferPool的大小应该是机器内存的50~60%
- BufferPool总大小 = (chunk大小 * bufferPool数量)* 系数
查看数据库属性
show engine innodb status
Total memory allocated XXXX;
Dictionary memory allocated XXX;
Buffer Pool Size XXX;
Free Buffer XXX; 说明free链表中有多少个缓存页是可以用的
Database pages XXX; 说明lru链表中有多少个缓存页
Old database pages XXX; 冷数据页区中的数量
Modified db pages XXX; flush链表中的缓存页数量
Pending reads; 磁盘上等待加载进缓存的数据页数量
Pending writes: LRU 0, flush list 0, single page0 即将从lru链表刷回磁盘的数量,即将从flush中刷回磁盘的数量
Pages made young XXX, not young XXX 已经从lru冷数据区转移到热数据页区的数量,以及在冷数据页区1s内被访问了,还没进入热数据区的数量
xx youngs/s, xx non-youngs/s
Pages read XXX, create xxx, written xxx 说明已经读取了、创建、写入了多少个缓存页,
xx reads/s, xx creates/s, 1xx writes/s
Buffer Pool hit rate xxx / 1000, young-making rate xxx / 1000 not xxx / 1000 每1000次访问,命中bufferPool多少次
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
Lru len:xxx, unzip_LRU len:xxx lru链表中缓存页的数量
I/O sum[xxx]:cur[xx], unzip sum[16xx:cur[0]] 50s读取磁盘页的总数,现在正在读取磁盘页的总数