MySQL进阶突击系列(08)年少不知BufferPool核心原理 | 大哥送来三条大金链子LRU、Flush、Free

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 本文深入探讨了MySQL中InnoDB存储引擎的buffer pool机制,包括其内存管理、数据页加载与淘汰策略。Buffer pool作为高并发读写的缓存池,默认大小为128MB,通过free链表、flush链表和LRU链表管理数据页的存取与淘汰。其中,改进型LRU链表采用冷热分离设计,确保预读机制不会影响缓存公平性。文章还介绍了缓存数据页的刷盘机制及参数配置,帮助读者理解buffer pool的运行原理,优化MySQL性能。

今日笔记:“自我完整”的人,不管遇到什么挫折,都能维持一整感觉--我在这儿,我相信自己有能力面对生活的挑战。如果出现挫折,能客观对待,既不归罪别人,也不容易怪罪自己,并且懂的安抚自己的挫败感,同时去寻找资源帮助自己。

相反,“未形成自我或自我破碎”的人,遇到挫折,就会觉得“我”被瓦解了,挫败感非常强烈,需要归罪,甩给其他人。


一、前言背景

二、bufferpool是什么?

2.1 数据在bufferpool 是如何存取的?一行一行数据来加载的吗?

2.2 怎么知道数据页是否在缓存池?

三、bufferpool如何管理这些数据页?

3.1 free链表-可用数据页

3.2 flush链表-脏数据页

3.3 free链表可用数据页不足,如何淘汰缓存页?

3.4 LRU链表-淘汰数据页

3.4.1 InnoDB的预读机制

3.4.2 传统LRU链表

3.4.3 改进型LRU链表-1分为2冷热分离设计

3.5 缓存数据页刷盘机制


一、前言背景

通过前面7篇系列文章,我们已经初步了解MySQL整体架构、三大日志法宝、事务隔离级别、锁、mvcc机制、索引优化等相关领域,然而鲜有人知但非常重要的bufferpool同样值得深入探讨学习。InnoDB高效的读写表现,bufferpool提供内存级别的读写管理能力,功不可没。

本文通过bufferpool的free链表、flush链表、lru链表来详细分析缓存池数据页加载、淘汰、刷盘等多个核心机制,希望对大家理解bufferpool运行原理有些许帮助。

二、bufferpool是什么?

作为MySQL高并发读写核心模块,buffer pool是一块基于内存的数据缓存池,默认大小是128Mb。

show variables like '%buffer_pool%';

如果MySQL服务器内存够大,比如16G、32G,可以考虑适当调整buffer pool大小到2G、4G,充分发挥服务高配置的优势,有效提升MySQL读写性能。

bufferpool的内存区域是一片连续的内存区域,里面就是按数据页来划分管理,可以把它想象为一个个16kb大小的数据块拼装成的128Mb 的缓存池。数据库数据逻辑概念,数据库是库、表、行来划分,习惯性的认为数据读写是一行一行的读取更新。实际上,在MySQL数据存储读写最小单元是【数据页】。

每个数据页大小是16Kb,通过命令查询innodb_page_size参数:show variables like '%page_size%';

这个参数不能在运行时修改,上线运行后不应该再次修改,影响非常大。

此外,MySQL的InnoDB存储引擎,支持bufferpool多实例配置,可以提升并发读写性能。


2.1 数据在bufferpool 是如何存取的?一行一行数据来加载的吗?

数据页在内存划分是紧密相连的,可以有效避免内存碎片。每个数据页里除了存放真实数据外,还有数据页号、所属表空间、在缓存池的地址等描述信息。

此外,在磁盘里也是以一个个数据页为最小单元去存取数据,当数据页被用到的时候,就会被加载到缓存池。

2.2 怎么知道数据页是否在缓存池?

当MySQL需要查询一个数据时,需要先判断该数据对应的数据页是否存在bufferpool。

MySQL有个数据页缓存记录hash表,key=表空间号+数据页号,value是=数据页地址。如果该记录表能找到对应数据页key,说明已缓存到bufferpool。否则就需要从磁盘里加载数据页到bufferpool里。


三、bufferpool如何管理这些数据页?

3.1 free链表-可用数据页

为了记录每个数据页是否空闲,bufferpool设计了一个free链表-双向链表,来记录当前缓存池空闲的数据页。如果某个数据页加载存放了数据,该数据页的描述信息就会从free链表移除。

3.2 flush链表-脏数据页

MySQL给bufferpool缓存池维护一个flush链表,用来记录哪些数据页已经被修改过,需要刷到磁盘的脏数据页。如果某个被数据页被修改过,该数据页的描述信息被加入flush链表的节点。flush链表和free链表几乎是一样的,里面主要存放的也是数据页的描述信息,非常轻巧,没有多少数据冗余。

3.3 free链表可用数据页不足,如何淘汰缓存页?

随着时间推移,bufferpool加载进来的数据页越来越多,最终free链表无可用空闲数据页存放新加载数据。此时需要对缓存里的数据页进行筛选淘汰那些命中率低、缓存价值低的数据页。而缓存命中价值通过另一个链表-LRU链表来记录判断。


3.4 改进型LRU链表-淘汰数据页

LRU,全称是least recently used最近最少使用。LRU链表也是双向链表,和free、flush链表类似,里面也是数据页的描述信息。那InnoDB的改进型LRU链表如何设计,和传统的LRU算法有什么区别?我们先了解read ahead预读机制,和传统LRU链表。

3.4.1 InnoDB的预读机制

InnoDB read ahead预读机制:InnoDB在执行加载某些数据页的时候,认为后期会读到某些数据页,就预先把部分非目标数据页一起加载到bufferpool中。预读机制有2种子类型:线性预读和随机预读。

线性预读:参数innodb_read_ahead_threshold=56,这个参数含义是当顺序加载一个数据区(extent)数据页数量大于56个时,就会把相邻数据区(extent)中的全部数据页预读进来。

随机预读:参数innodb_random_read_ahead是关闭的。如果打开该参数为ON,当在一个数据区随机加载了13个数据页,就直接把该数据区其他数据页全部加载到bufferpool。

综上所述,InnoDB默认情况下,只会触发线性预读。也就是当顺序访问一个区多个数据页,数量大于56,就会把下一个相邻数据区全部数据页加载进bufferpool。这种情况,就让bufferpool里一下子多了很多可能不会被用到的数据页。

比如,某些SQL触发了全表扫描,bufferpool就被迫加载了全表数据到bufferpool,bufferpool可用空闲数据页很快就会被占满,淘汰数据页的考虑就迫在眉睫。

3.4.2 传统LRU链表

如果按普通LRU最近最少使用链表设计,当bufferpool加载一个数据页进来时,LRU链表就会把该数据页描述信息放置到LRU链表头部节点,后续如果查询命中、或者修改了该数据页,该数据页描述信息也会被挪到LRU链表头部。这样LRU链表的尾部节点,一定是最近最少被使用的节点。淘汰数据页就从LRU尾部进行淘汰。

但是刚才InnoDB 预读机制来看,传统简单的LUR链表,之前被频繁访问修改的数据页,很可能被预加载进来的其他没有价值的数据页一下子排挤到LRU链表的尾部。比如数据页C本来是LRU链表头部节点,最近1min被访问了100次,但是由于最近一次全表扫描、或者触发了线性预读,下一个数据区的不需要的数据页B等多个数据页被加载进来,数据页C直接被LRU挪到尾部,面临被淘汰的风险。这个传统简单LRU设计,在预读机制影响下,并不合理公平,需要改进。

3.4.3 改进型LRU链表-1分为2冷热分离设计

bufferpool的LRU链表是经过优化改进的链表,它的设计和优化思路值得参考学习。具体是:LRU链表,一分为二,有热数据区+冷数据区组成链表。

冷热数据占比情况,通过参数innodb_old_blocks_pct配置,默认冷数据占比37%,热数据63%,大概是46开占比。

当数据页首次被加载到bufferpool后,不是直接放到LRU链表头部,而是放在LRU链路冷数据区部分的头部。

此外,数据页描述信息节点进入冷数据区头部后,需要经过innodb_old_blocks_time(默认是1000ms)后,也就是1s后,如果有被再次访问,才能被挪到热数据区的头部,也就是整个LRU链表的头部。

这个LRU链表冷热分离,以及数据页从冷数据到成为真正热数据的规则的设计,可以有效避免预读机制对LRU淘汰公平性破坏。

最后,MySQL在热数据区里也继续做了优化,在LRU热数据区只有后75%的数据页被访问了,才会挪到热数据区头部。前面25%被访问的数据页不会再次修改LRU链表,这样可以有效避免LRU链表因为那些top级火热的数据,频繁访问引起LRU节点变化影响性能。


3.5 缓存数据页刷盘机制

当bufferpool存满后,free链表没有可用空闲数据页,必须要刷盘。当然也不是一定要等到bufferpool没有可用数据页空间才刷盘。MySQL有个定时线程专门负责将LRU链表尾部冷数据以及flush链表脏数据刷盘。该线程会定时把lru链表尾部未被修改的数据直接释放掉,给free链表增加可用数据页。也会从flush链表找那些已经被修改过的脏数据页刷到磁盘,然后增加到free链表。

这里有个参数innodb_lru_scan_depth,用来设置LRU列表中可用页的数量,默认是1024。当lru可用数据页节点数量小于1024时,会发生checkpoint,需要移除LRU列表冷数据区部分数据页。

综上,bufferpool核心运行原理大致如下:当bufferpool加载一个数据页后,free链表移除该数据页描述信息节点,而lru链表会在冷数据区头部新增该数据页描述信息节点。当该数据页被修改后,flush链表会新增该数据页描述信息节点,此外lru链表会把该数据页从冷数据区移动到热数据区,或者在热数据区后75%的位置挪到lru热数据区头部位置。当触发刷盘策略后,lru链表的冷数据或者flush表对应的脏数据页,会被优先刷盘或者从对应链表移除释放,提供新的free可用数据页节点。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
2月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
6月前
|
自然语言处理 搜索推荐 关系型数据库
MySQL实现文档全文搜索,分词匹配多段落重排展示,知识库搜索原理分享
本文介绍了在文档管理系统中实现高效全文搜索的方案。为解决原有ES搜索引擎私有化部署复杂、运维成本高的问题,我们转而使用MySQL实现搜索功能。通过对用户输入预处理、数据库模糊匹配、结果分段与关键字标红等步骤,实现了精准且高效的搜索效果。目前方案适用于中小企业,未来将根据需求优化并可能重新引入专业搜索引擎以提升性能。
277 5
|
2月前
|
SQL 关系型数据库 MySQL
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
|
7月前
|
关系型数据库 MySQL 数据库
RDS用多了,你还知道MySQL主从复制底层原理和实现方案吗?
随着数据量增长和业务扩展,单个数据库难以满足需求,需调整为集群模式以实现负载均衡和读写分离。MySQL主从复制是常见的高可用架构,通过binlog日志同步数据,确保主从数据一致性。本文详细介绍MySQL主从复制原理及配置步骤,包括一主二从集群的搭建过程,帮助读者实现稳定可靠的数据库高可用架构。
404 9
RDS用多了,你还知道MySQL主从复制底层原理和实现方案吗?
|
6月前
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
126 16
|
6月前
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
105 4
|
7月前
|
缓存 关系型数据库 MySQL
图解MySQL【日志】——Buffer Pool
Buffer Pool 是数据库管理系统(DBMS)中用于缓存磁盘数据页的内存区域,主要包含数据页、索引页、undo 页等。它通过减少磁盘 I/O 提升性能,特别是在处理大型数据库时效果显著。查询时,整个数据页而非单条记录会被加载到 Buffer Pool 中,以提高访问效率。
117 0
图解MySQL【日志】——Buffer Pool
|
3月前
|
人工智能 运维 关系型数据库
数据库运维:mysql 数据库迁移方法-mysqldump
本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
665 1
|
4月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
3月前
|
SQL 关系型数据库 MySQL
Go语言数据库编程:使用 `database/sql` 与 MySQL/PostgreSQL
Go语言通过`database/sql`标准库提供统一数据库操作接口,支持MySQL、PostgreSQL等多种数据库。本文介绍了驱动安装、连接数据库、基本增删改查操作、预处理语句、事务处理及错误管理等内容,涵盖实际开发中常用的技巧与注意事项,适合快速掌握Go语言数据库编程基础。
258 62

相关产品

  • 云数据库 RDS MySQL 版
  • 推荐镜像

    更多