1.1 上期回顾
在上篇文章中,我们提到了因为msyql的预读机制,可能会把相邻的一些数据页读取到缓存页中,而且这些缓存页,会放在lru的头部,可能会导致经常命中的缓存页挤到尾部,从而导致释放一些经常被访问的缓存页,所以这一篇文件将会继续分析
ps: 刚看了公司的年会,抽奖什么的环节都没有了,难受啊,杭州环境还是这么差了,公司市值只有不到50亿了
1.2 基于冷热数据分离思想的LRU链表
所以正是由于预读机制带来的问题,mysql在真正设计LRU,采取的事冷热数据分离的思想
冷热分离思想 1.把LRU分成两部分,冷数据占37%,热数据占63%,如图所示:
2.数据第一次加载到缓存页,会放在冷数据里面,在后面某个时机被使用的时候,会移动到热数据中
但是什么时候会从冷数据移动到热数据中呢? 很多人肯定会想,只要对冷数据中的缓存页访问一次,就会移动到热数据中;这样其实是不合理的,比如你把刚刚加载一个数据页到缓存页,此时他在冷数据链的头部,然后立马(几毫秒之内就访问了),之后就不在访问了,这个时候把他放在热数据区域,这样肯定不合理的; 实际上mysql还会通过一个参数innodb_old_blocks_time来控制,这个参数 innodb_old_blocks_time = 1000,单位是毫秒,也就是说,数据被加载到缓存页后,必须在1秒后访问,mysql就认为这个数据可能才是你以后真正会经常访问的数据,才会把缓存页从冷数据链移动到热数据链表头,如下图
1.3 几种场景分析冷热数据
1.3.1 预读和全表扫描的数据
在全表扫描情况下,如果这个时候热数据里面有频繁访问的缓存页,只要热数据区有缓存页被访问,他还是会被移动到热数据的头部的,这个时候新缓存进来的数据,都会依次放在冷数据的头部,这个时候如果1秒后继续访问冷数据中的缓存页,这个缓存页也是会移动到热数据链表中
1.3.2 缓存页不够,要淘汰哪些数据?
需要淘汰一些数据,首先肯定从冷数据中选择,冷数据头部是最新加载的数据,肯定是最近需要的,那么只需要从冷数据尾部拿一些数据,刷新到磁盘中,就能释放这些缓存页了
1.4 热数据中的数据,访问一次就会立马移动到头部吗?
还有一个问题,需要我们来思考下: 既然数据在热数据中,那么被访问的频率肯定是比较高的,如果访问一次就直接移动到最前面,那么这样的话,频繁的移动也是对性能的损耗,这个时候mysql又设计了一个比较优雅的地方:
在热数据区,如果这个被访问的缓存页在前25%,就不会移动了,只有在后25%范围内,每次访问的时候才被移动到头部,这样就能大大减少一些不必要的移动而造成的损失,如下图:
1.5总结
随着这几篇文章的分析,buffer pool中会有free链表,flush链表,lru链表,
1.当数据页从磁盘加载到内存中,free链表会移除这个缓存页,然后lru链表的冷数据区域头部会放入这个缓存页
2.如果要是修改这个缓存页,会在flush链表中记录这个缓存页,同时lru链表会把这个数据从冷数据区移动到热数据区的头部
3.如果只是查询这个数据,会从lru冷数据区移动到热数据头部,或者这个数据之前就在热数据区,如果在后3/4范围内,也有可能会移动到头部
4.如果缓存页满了,这个及时需要清空一切缓存页,就会从lru的冷数据区尾部找一些数据刷新到磁盘上.
5.msyql并不是要等缓存页用完了才会刷新释放缓存页,而是会有一个定时任务,定期从lru冷数据的尾部选择一些数据页来刷新,清空几个缓存页,把他们添加到free链表中
二.Buffer Pool可以优化的点
在前面讲解我们知道,msyql操作,实际就是操作Buffer Pool,但是如果只有一个buffer pool,那么mysql在接收多个请求的时候,会开启多个线程,这个时候,多线程对buffer中的数据进行操作,肯定是需要加锁的,然而这种操作都是操作内存,所以速度基本上也是很快的,实际线上环境,我们可以根据自己服务器大小,合理设置buffer pool的大小,从而进一步提高并发
show variables like 'innodb_buffer_pool_instances'
参数默认是1,可以根据服务器大小,合理设置, 比如buffer大小设置为4G,innodb_buffer_pool_instances就可以设为4,就是设置四个buffer pool,每个大小是1G
推荐 buffer pool 设置的内存数量是服务器的40--50%是比较合理的
三.为什么不直接修改磁盘的数据
通过学习,我们知道mysql为了修改数据,设计复杂的bufferpool,free链表,flush链表,lru链表,以及redo log,undo log,为什么不直接对insert和update语句直接修改磁盘的数据呢?
答案就是性能! 因为一个请求,就是对磁盘的随机读取,磁盘随机读取的性能是很差的,随机修改磁盘数据,当并发量大一点,mysql就扛不住了,所以MySQL才设计了如此复杂的一套机制,通过内存里更新数据,然后写redo log以及事务提交,后台线程不定时刷新内存里的数据到磁盘文件里,通过这种方式保证,你每个更新请求,尽量就是更新内存,然后顺序写日志文件。更新内存的性能是极高的,然后顺序写磁盘上的日志文件的性能也是比较高的,因为顺序写磁盘文件,他的性能要远高于随机读写磁盘文件。也正是通过这套机制,才能让我们的MySQL数据库在较高配置的机器上,每秒可以抗下几千的读写请求。
结束语
这篇文章是春节前写好的,本来想着春节期间在补充完善一些内容,春节回去,就再也没有打开电脑,唉