Innodb 架构:Buffer Pool

innodb架构

buffer pool 简介

Buffer pool 是mysql的内存结构之一,如果每次读写都要直接磁盘IO,会大大拖慢执行效率,这就是引入buffer pool的原因。buffer pool的结构如下:

缓存页与磁盘页对应,默认16KB。为了管理这些页,引入了控制块,控制块保存了这些页的元信息,主要有:

  1. 表空间编号
  2. 页号
  3. 缓存页在buffer pool的地址
  4. 链表节点指针
  5. 锁信息
  6. LSN信息

与buffer pool一同参与管理的有三个主要的链表:free链表,flush链表,LRU链表。下面分别介绍。

缓存页的哈希处理

如果要访问的数据所在的页已经被加载到buffer pool中,我们就可以直接读写内存。但要如何知道一个页已经被加载到pool中呢?我们通过表空间+页号来标识一个页,因此可以构建一个哈希表:

key:表空间编号+页号

value:控制块

free链表

如果要加载一页到buffer pool中,如何知道哪个缓存页是空闲的呢?这就是free链表提出的背景。mysql刚启动时,所有的缓存页都处于free链表中,每当从磁盘加载一页到pool中时,就从free链表取出一个空闲的缓存页。把该页对应的控制块信息填上(表空间,页号),然后该缓存页对应的节点从free链表移除。

flush链表

如果我们修改了某个页(dirty page),这个页会被加入flush链表,等待刷盘。flush链表的结构和free链表类似。

LRU链表

Buffer pool的空间是有限的,如果需要加载一个新页,但free链表已经用光了,该怎么办?这就是LRU链表提出的背景。当缓存页被写入后,该页从free链表移除,加入LRU链表的头部。但这里有两个情况需要考虑:

  1. Innodb 提供预读功能,当innodb认为后续请求可能会访问某些页面,它会提前把这些页面加载到buffer pool,但这些页面后续可能用不到,白白占用了空间;

    1. 预读分为两种:
      1. 线性预读:如果顺序访问某个区的页面超过某个值(innodb_read_ahead_threshold),innodb就会将下个区的全部页面加载到buffer pool;
      2. 随机预读:如果buffer pool已经缓存了某个区的13个连续页面,不论这些页面是否是顺序读取的,都会触发一次预读,将本区所有其他页面加载到buffer pool,这个功能通过 innodb_random_read_ahead 控制,默认OFF;
  2. 全表扫描,会将很多页面放入buffer pool,将buffer pool换血,但这些页面后续很少被访问到。如果这时还有业务数据在读取其他页面,那这些页面就被从buffer pool挤了出去;

上述两个问题都是劣币驱逐良币,为了解决这一点,LRU链表进行了分区。old区的比例由 innodb_old_blocks_pct 控制,默认值37,代表old区占的比例是37%。

规则如下:

  1. 页加载时会放到old区的头节点
  2. 访问old区页面的时候,记录第一次访问的时间,如果后续访问时间与第一次访问时间不超过某个阈值(innodb_old_blocks_time )默认1s,那该页面就不会被移动到young区,否则移动到young区头部

第一点对应预读,避免预读加载的页影响young区域活跃的缓存页;

第二点对应全表扫描,扫描时某个页会在短时间内被大量访问,之后就不再访问。如果这种高频访问都在阈值内(在一次全表扫描的过程中,多次访问一个页面中的时间不会超过1s),我们就不移动缓存页;

刷新脏页到磁盘

  1. 从LRU链表尾部刷脏(BUF_FLUSH_LRU),后台线程会定时从LRU链表尾部扫描一些页面,扫描数量通过 innodb_lru_scan_depth 控制,如果这些页里有脏页,会把他们刷新到磁盘;
  2. 从flush链表刷脏(BUF_FLUSH_LIST),后台线程会定时从flush链表刷脏;

有时候后台线程刷脏比较慢,导致用户线程加载页面时没有可用的缓存页,这时用户线程就会尝试将LRU链表尾部的脏页同步刷新到磁盘,这被称作BUF_FLUSH_SINGLE_PAGE,是个很慢的操作。

多个buff pool实例

为了提高并发度,innodb_buffer_pool_instances 管理buff pool实例个数,每个实例是彼此独立的。每个buffer pool占用的空间:

innodb_buffer_pool_size / innodb_buffer_pool_instances

随着多实例的引入,还提出了chunk的概念,每次申请内存以chunk为单位:

innodb_buffer_pool_chunk_size 设置了chunk的大小,默认128M。

innodb_buffer_pool_size 必须是 innodb_buffer_pool_chunk_size × innodb_buffer_pool_instances 的倍数,这是为了保证每个buffer pool实例包含的chunk数量相同

Buff pool 状态信息

bash 复制代码
mysql> SHOW ENGINE INNODB STATUS\G
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 13218349056;
Dictionary memory allocated 4014231
Buffer pool size   786432
Free buffers       8174
Database pages     710576
Old database pages 262143
Modified db pages  124941
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 6195930012, not young 78247510485
108.18 youngs/s, 226.15 non-youngs/s
Pages read 2748866728, created 29217873, written 4845680877
160.77 reads/s, 3.80 creates/s, 190.16 writes/s
Buffer pool hit rate 956 / 1000, young-making rate 30 / 1000 not 605 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 710576, unzip_LRU len: 118
I/O sum[134264]:cur[144], unzip sum[16]:cur[0]
  1. Total memory allocated:buffer pool 总大小;
  2. buffer pool size:Buffer Pool 可以容纳多少缓存页,注意,单位是页!
  3. Free buffers:还有多少空闲页,也就是free链表节点数;
  4. Database pages:LRU链表页数量;
  5. Old database pages:LRU old区页数量;
  6. Modified db pages:脏页数量,也就是flush链表节点数;
  7. Pending reads:等待从磁盘加载的页面数量;
  8. Pending writes:即将从(LRU,flush链表,单页)刷新到磁盘的页数量;
  9. Pages read,created,written:读取,创建,写入了多少页。后边跟着读取、创建、写入的速率;
  10. Buffer pool hit rate:缓存命中率;
  11. I/O sum:最近50s读取磁盘页的总数;
  12. I/O cur:现在正在读取的磁盘页数量;

参考

  1. 第18章 调节磁盘和CPU的矛盾-InnoDB的Buffer Pool (relph1119.github.io)
  2. dev.mysql.com/doc/refman/...
相关推荐
.生产的驴9 分钟前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
爱学的小涛17 分钟前
【NIO基础】基于 NIO 中的组件实现对文件的操作(文件编程),FileChannel 详解
java·开发语言·笔记·后端·nio
爱学的小涛18 分钟前
【NIO基础】NIO(非阻塞 I/O)和 IO(传统 I/O)的区别,以及 NIO 的三大组件详解
java·开发语言·笔记·后端·nio
北极无雪22 分钟前
Spring源码学习:SpringMVC(4)DispatcherServlet请求入口分析
java·开发语言·后端·学习·spring
hefaxiang26 分钟前
【MYSQL】mysql约束---自增长约束(auto_increment)
数据库·mysql
爱码少年28 分钟前
springboot工程中使用tcp协议
spring boot·后端·tcp/ip
计算机学姐1 小时前
基于微信小程序的调查问卷管理系统
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis
2401_857622668 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_857589368 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
哎呦没10 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端