MySQL 性能优化 InnoDB buffer pool flush策略漫谈(2)

在之前版本中,因为可能同时有多个线程操作buffer pool刷page (在刷脏时会释放buffer pool mutex),每次刷完一个page后需要回溯到链表尾部,使得扫描bp链表的时间复杂度最差为O(N*N)。

在5.6版本中针对Flush list的扫描做了一定的修复,使用一个指针来记录当前正在flush的page,待flush操作完成后,再看一下这个指针有没有被别的线程修改掉,如果被修改了,就回溯到链表尾部,否则无需回溯。但这个修复并不完整,在最差的情况下,时间复杂度依旧不理想。

因此在5.7版本中对这个问题进行了彻底的修复,使用多个名为hazard pointer的指针,在需要扫描LIST时,存储下一个即将扫描的目标page,根据不同的目的分为几类:

flush_hp: 用作批量刷FLUSH LIST

lru_hp: 用作批量刷LRU LIST

lru_scan_itr: 用于从LRU链表上驱逐一个可替换的page,总是从上一次扫描结束的位置开始,而不是LRU尾部

single_scan_itr: 当buffer pool中没有空闲block时,用户线程会从FLUSH LIST上单独驱逐一个可替换的page 或者 flush一个脏页,总是从上一次扫描结束的位置开始,而不是LRU尾部。

后两类的hp都是由用户线程在尝试获取空闲block时调用,只有在推进到某个buf_page_t::old被设置成true的page (大约从Lru链表尾部起至总长度的八分之三位置的page)时, 再将指针重置到Lru尾部。

这些指针在初始化buffer pool时分配,每个buffer pool instance都拥有自己的hp指针。当某个线程对buffer pool中的page进行操作时,例如需要从LRU中移除Page时,如果当前的page被设置为hp,就要将hp更新为当前Page的前一个page。当完成当前page的flush操作后,直接使用hp中存储的page指针进行下一轮flush。


社区优化

一如既往的,Percona Server在5.6版本中针对buffer pool flush做了不少的优化,主要的修改包括如下几点:

优化刷LRU流程buf_flush_LRU_tail
该函数由page cleaner线程调用。

原生的逻辑:依次flush 每个buffer pool instance,每次扫描的深度通过参数innodb_lru_scan_depth来配置。而在每个instance内,又分成多个chunk来调用;

修改后的逻辑为:每次flush一个buffer pool的LRU时,只刷一个chunk,然后再下一个instance,刷完所有instnace后,再回到前面再刷一个chunk。简而言之,把集中的flush操作进行了分散,其目的是分散压力,避免对某个instance的集中操作,给予其他线程更多访问buffer pool的机会。

允许设定刷LRU/FLUSH LIST的超时时间,防止flush操作时间过长导致别的线程(例如尝试做single page flush的用户线程)stall住;当到达超时时间时,page cleaner线程退出flush。

避免用户线程参与刷buffer pool
当用户线程参与刷buffer pool时,由于线程数的不可控,将产生严重的竞争开销,例如free list不足时做single page flush,以及在redo空间不足时,做dirty page flush,都会严重影响性能。Percona Server允许选择让page cleaner线程来做这些工作,用户线程只需要等待即可。出于效率考虑,用户还可以设置page cleaner线程的cpu调度优先级。
另外在Page cleaner线程经过优化后,可以知道系统当前处于同步刷新状态,可以去做更激烈的刷脏(furious flush),用户线程参与到其中,可能只会起到反作用。

允许设置page cleaner线程,purge线程,io线程,master线程的CPU调度优先级,并优先获得InnoDB的mutex。

使用新的独立后台线程来刷buffer pool的LRU链表,将这部分工作负担从page cleaner线程剥离。
实际上就是直接转移刷LRU的代码到独立线程了。从之前Percona的版本来看,都是在不断的强化后台线程,让用户线程少参与到刷脏/checkpoint这类耗时操作中。

MySQL InnoDB表--BTree基本数据结构

在MySQL的InnoDB存储引擎中count(*)函数的优化

MySQL InnoDB存储引擎锁机制实验

InnoDB存储引擎的启动、关闭与恢复

MySQL InnoDB独立表空间的配置

MySQL Server 层和 InnoDB 引擎层 体系结构图

InnoDB 死锁案例解析

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/8d1007d6f3e7812672b1dd072dbe5701.html