《DBNotes:Buffer Pool刷脏页细节以及改进》

本笔记知识沿用之前DBNotes: Buffer Pool对于缓冲页的链表式管理的部分知识

目录

  • 获取一个空闲页的源码逻辑
  • Page_Cleaner_Thread
  • LRU_Manager_Thread
  • Hazard Pointer作为驱逐算法改进
  • 参考

获取一个空闲页的源码逻辑

任何一个读写请求都需要从Buffer pool来获取所需页面。如果需要的页面已经存在于Buffer pool,那么直接利用当前页面进行操作就行。但是如果所需页面不在Buffer pool,比如UPDATE操作,那么就需要从Buffer pool中新申请空闲页面,将需要读取的数据放到Buffer pool中进行操作。

如何从buffer pool中获取一个页面呢?这依赖于buf_LRU_get_free_block函数,该函数会循环尝试去淘汰LRU list上的页面。每次循环都会访问freelist,查看是否有足够的空闲页面,如果没有,就继续从LRUlist去淘汰。这样的循环在负载较高的时候会加剧对freelist以及LRUlist的mutex的竞争。可以设置buf_pool->try_LRU_scan是做了一个优化,如果当前用户线程扫描的时候 发现没有空闲页面,那么其他用户线程就不需要进行同样的扫描。

MySQL的free页面的获取依赖于Page_Cleaner_Thread的刷新能力,如果刷新不及时,那么系统就会使用上面所说的循环逻辑来为用户线程申请空闲页面,可以看出是十分耗时间的。而如果刷新过快,也会导致性能问题,因为刷新是需要io操作的。

所以引入独立的线程负责LRU list的刷脏。目的是为了让独立线程根据系统负载动态调整LRU的刷脏能力。由于LRU list的刷脏从page cleaner线程中脱离出来,调整LRU list的刷脏能力不再会影响到page cleaner。

同时由于单线程LRUlist刷脏存在问题,设计者进行了改进。继续将LRU list独立于page cleaner threads并将LRU list单线程刷脏增加为多线程刷脏。page cleaner只负责flush list的刷脏,lru_manager_thread只负责LRU List刷脏。这样的分离,可以使得LRU list刷脏和Flush List刷脏并行执行。

Page_Cleaner_Thread

主要负责flushlist的刷脏,避免用户线程同步刷脏页。

也是每隔一定时间刷一次脏页,sleep time是自适应的,依赖于当前的lsn,flushlist中的oldest_modification以及当前的同步刷脏点。

与LRU_Manager_Thread不同,该线程每次执行刷的脏页数量也是自适应的,依赖于当前系统中脏页的比率,日志产生的速度以及几个参数。

LRU_Manager_Thread

一个系统线程,随着InnoDB启动而work,作用是定期清理出空闲的数据页(数量为innodb_LRU_scan_depth)并加入到Freelist中,防止用户线程去做同步刷脏影响效率。

该线程每隔一段时间就去FLUSH。先尝试从LRU中驱逐部分数据页,如果数量不够就从Flushlist中驱逐。

线程执行频率是自适应的:

设定max_free_len = innodb_LRU_scan_depth * innodb_buf_pool_instances。

如果Freelist中的数量小于max_free_len 的1%,则sleep time = 0,表示这时候空闲页太少了,需要一直执行buf_flush_LRU_tail操作,从而腾出空闲的数据页。

如果Free List中的数量介于max_free_len的1%-5%,则sleep time减少50ms(默认为1000ms),如果Free List中的数量介于max_free_len的5%-20%,则sleep time不变,如果Free List中的数量大于max_free_len的20%,则sleep time增加50ms,但是最大值不超过rds_cleaner_max_lru_time

Hazard Pointer作为驱逐算法改进

在学术上,Hazard Pointer是一个指针,如果这个指针被一个线程所占有,在它释放之前,其他线程不能对他进行修改,但是在InnoDB里面,概念刚好相反,一个线程可以随时访问Hazard Pointer,但是在访问后,他需要调整指针到一个有效的值,便于其他线程使用。我们用Hazard Pointer来加速逆向的逻辑链表遍历。 先来说一下这个问题的背景,我们知道InnoDB中可能有多个线程同时作用在Flush List上进行刷脏,例如LRU_Manager_Thread和Page_Cleaner_Thread。同时,为了减少锁占用的时间,InnoDB在进行写盘的时候都会把之前占用的锁给释放掉。这两个因素叠加在一起导致同一个刷脏线程刷完一个数据页A,就需要回到Flush List末尾(因为A之前的脏页可能被其他线程给刷走了,之前的脏页可能已经不在Flush list中了),重新扫描新的可刷盘的脏页。另一方面,数据页刷盘是异步操作,在刷盘的过程中,我们会把对应的数据页IO_FIX住,防止其他线程对这个数据页进行操作。我们假设某台机器使用了非常缓慢的机械硬盘,当前Flush List中所有页面都可以被刷盘(buf_flush_ready_for_replace返回true)。我们的某一个刷脏线程拿到队尾最后一个数据页,IO fixed,发送给IO线程,最后再从队尾扫描寻找可刷盘的脏页。在这次扫描中,它发现最后一个数据页(也就是刚刚发送到IO线程中的数据页)状态为IO fixed(磁盘很慢,还没处理完)所以不能刷,跳过,开始刷倒数第二个数据页,同样IO fixed,发送给IO线程,然后再次重新扫描Flush List。它又发现尾部的两个数据页都不能刷新(因为磁盘很慢,可能还没刷完),直到扫描到倒数第三个数据页。所以,存在一种极端的情况,如果磁盘比较缓慢,刷脏算法性能会从O(N)退化成O(N*N)。 要解决这个问题,最本质的方法就是当刷完一个脏页的时候不要每次都从队尾重新扫描。我们可以使用Hazard Pointer来解决,方法如下:遍历找到一个可刷盘的数据页,在锁释放之前,调整Hazard Pointer使之指向Flush List中下一个节点,注意一定要在持有锁的情况下修改。然后释放锁,进行刷盘,刷完盘后,重新获取锁,读取Hazard Pointer并设置下一个节点,然后释放锁,进行刷盘,如此重复。当这个线程在刷盘的时候,另外一个线程需要刷盘,也是通过Hazard Pointer来获取可靠的节点,并重置下一个有效的节点。通过这种机制,保证每次读到的Hazard Pointer是一个有效的Flush List节点,即使磁盘再慢,刷脏算法效率依然是O(N)。 这个解法同样可以用到LRU List驱逐算法上,提高驱逐的效率。

参考

MySQL · 源码分析 · Innodb缓冲池刷脏的多线程实现
MySQL · 源码分析 · InnoDB LRU List刷脏改进之路
MySQL · 引擎特性 · InnoDB Buffer Pool

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/377061.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WordPress删除数据中标题重复文章的方法

一种是删除重复的方法是:使用插件,大家可以去官网上下载 二种删除重复的方法是:登录数据库,使用sql语句删除,具体的语句为如下代码: CREATE TABLE my_tmp AS SELECT MIN(ID) AS col1 FROM wp_posts GROUP BY post_titl…

hibernate配置

hibernate.cfg.xml <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd&quo…

html中表单元素_HTML中的表单元素

html中表单元素1)<input>元素 (1) The <input> Element) The <input> element is used to get input from the user in an HTML form. <input>元素用于以HTML形式从用户获取输入。 <input> tag is used to get input using input element, the …

《搜索算法——DFS、BFS、回溯》

目录深搜200. 岛屿数量695. 岛屿的最大面积130. 被围绕的区域547. 省份数量417. 太平洋大西洋水流问题回溯广搜111. 二叉树的最小深度752. 打开转盘锁深搜与广搜结合934. 最短的桥深搜 深搜DFS&#xff0c;在搜索到一个新节点时&#xff0c;立即对该新节点进行遍历&#xff0c…

AP in R

AP聚类算法是目前十分火的一种聚类算法&#xff0c;它解决了传统的聚类算法的很多问题。不仅简单&#xff0c;而且聚类效果还不错。这里&#xff0c;把前两天学习的AP算法在R语言上面的模拟&#xff0c;将个人笔记拿出来与大家分享一下&#xff0c;不谈AP算法的原理&#xff0c…

nginx 模块解析

nginx的模块非常之多&#xff0c;可以认为所有代码都是以模块的形式组织&#xff0c;这包括核心模块和功能模块&#xff0c;针对不同的应用场合&#xff0c;并非所有的功能模块都要被用到&#xff0c;附录A给出的是默认configure&#xff08;即简单的http服务器应用&#xff09…

python关键字和保留字_Python关键字

python关键字和保留字关键词 (Keywords) Keywords are the reserved words in Python programming language (and, any other programming languages like C, C, Java, etc) whose meanings are defined and we cannot change their meanings. In python programming languages…

《LeetcodeHot100非困难题补录》

最近比较闲&#xff0c;也比较焦虑&#xff0c;刷刷题吧 目录11. 盛最多水的容器22. 括号生成31. 下一个排列48. 旋转图像49. 字母异位词分组56. 合并区间75. 颜色分类79. 单词搜索114. 二叉树展开为链表141. 环形链表148. 排序链表152. 乘积最大子数组169. 多数元素207. 课程表…

Java里String.split需要注意的用法

我们常常用String的split()方法去分割字符串&#xff0c;有两个地方值得注意&#xff1a; 1. 当分隔符是句号时(".")&#xff0c;需要转义&#xff1a; 由于String.split是基于正则表达式来分割字符串&#xff0c;而句号在正则表达式里表示任意字符。 //Wrong: //Str…

C# Socket 例子(控制台程序)

服务器代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.IO;namespace TCPListener {class Program{static void Main(string[] args){const int BufferSize 1024;Con…

Scala中的值类

Value classes are a special mechanism in Scala that is used to help the compiler to avoid allocating run time objects. 值类是Scala中的一种特殊机制&#xff0c;用于帮助编译器避免分配运行时对象。 This is done by defining a subclass of AnyVal. The only parame…

《MySQL8.0.22:Lock(锁)知识总结以及源码分析》

目录1、关于锁的一些零碎知识&#xff0c;需要熟知事务加锁方式&#xff1a;Innodb事务隔离MVCC多版本并发控制常用语句 与 锁的关系意向锁行级锁2、锁的内存结构以及一些解释3、InnoDB的锁代码实现锁系统结构lock_sys_tlock_t 、lock_rec_t 、lock_table_tbitmap锁的基本模式的…

关于ORA-04021解决办法(timeout occurred while waiting to lock object)

某个应用正在锁定该表或者包 表为 select b.SID,b.SERIAL#,c.SQL_TEXT from v$locked_object a, v$session b, v$sqlarea c where a.SESSION_ID b.SID and b.SQL_ADDRESS c.ADDRESS and c.sql_text like %table_name% 包为 select B.SID,b.USERNAME,b.MACHINE FROM V$ACCESS …

HtmlAutoTestFrameWork

前段时间做的自动化测试的是Silverlight的&#xff0c;框架都已经搭好。突然测试发现这里还有一个要发送邮件的html页面&#xff0c;并且将另外启动浏览器&#xff0c;于是今天下午把这个html的也写出来。用法 &#xff1a; HtmlAutoTestFrameWork htf new HtmlAutoTestFrameW…

L8ER的完整形式是什么?

L8ER&#xff1a;稍后 (L8ER: Later) L8ER is an abbreviation of "Later". L8ER是“ Later”的缩写 。 It is an expression, which is commonly used in messaging or chatting on social media networking sites like Facebook, Yahoo Messenger, and Gmail, etc…

Randomize select algorithm 随机选择算法

从一个序列里面选择第k大的数在没有学习算法导论之前我想最通用的想法是给这个数组排序&#xff0c;然后按照排序结果返回第k大的数值。如果使用排序方法来做的话时间复杂度肯定至少为O&#xff08;nlgn&#xff09;。 问题是从序列中选择第k大的数完全没有必要来排序&#xff…

《Linux杂记:一》

目录CPU负载和CPU利用率CPU负载很高,利用率却很低的情况负载很低,利用率却很高常用linux命令常用的文件、目录命令常用的权限命令常用的压缩命令CPU负载和CPU利用率 可以通过 uptime , w 或者 top 命令看到CPU的平均负载。 Load Average :负载的3个数字,比如上图的0.57、0.4…

IOS Plist操作

代码&#xff1a;copy BUNDLE下的plist文件 到 library下面。 bundle下不支持些&#xff0c;library&#xff0c;doc路径支持读与写。 (void)copyUserpigListToLibrary {NSFileManager *fileManager [NSFileManager defaultManager];NSArray *paths NSSearchPathForDirector…

《线程管理:线程基本操作》

目录线程管理启动线程与&#xff08;不&#xff09;等待线程完成特殊情况下的等待&#xff08;使用trycath或rall&#xff09;后台运行线程线程管理 启动线程与&#xff08;不&#xff09;等待线程完成 提供的函数对象被复制到新的线程的存储空间中&#xff0c;函数对象的执行…

scala特质_Scala的特质

scala特质Scala特质 (Scala traits) Traits in Scala are like interfaces in Java. A trait can have fields and methods as members, these members can be abstract and non-abstract while creation of trait. Scala中的特性类似于Java中的接口 。 特征可以具有作为成员的…