innodb架构
buffer pool 简介
Buffer pool 是mysql的内存结构之一,如果每次读写都要直接磁盘IO,会大大拖慢执行效率,这就是引入buffer pool的原因。buffer pool的结构如下:
缓存页与磁盘页对应,默认16KB。为了管理这些页,引入了控制块,控制块保存了这些页的元信息,主要有:
与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链表的头部。但这里有两个情况需要考虑:
Innodb 提供预读功能,当innodb认为后续请求可能会访问某些页面,它会提前把这些页面加载到buffer pool,但这些页面后续可能用不到,白白占用了空间;
全表扫描,会将很多页面放入buffer pool,将buffer pool换血,但这些页面后续很少被访问到。如果这时还有业务数据在读取其他页面,那这些页面就被从buffer pool挤了出去;
上述两个问题都是劣币驱逐良币,为了解决这一点,LRU链表进行了分区。old区的比例由 innodb_old_blocks_pct 控制,默认值37,代表old区占的比例是37%。
规则如下:
第一点对应预读,避免预读加载的页影响young区域活跃的缓存页;
第二点对应全表扫描,扫描时某个页会在短时间内被大量访问,之后就不再访问。如果这种高频访问都在阈值内(在一次全表扫描的过程中,多次访问一个页面中的时间不会超过1s),我们就不移动缓存页;
刷新脏页到磁盘
BUF_FLUSH_LRU
),后台线程会定时从LRU链表尾部扫描一些页面,扫描数量通过 innodb_lru_scan_depth 控制,如果这些页里有脏页,会把他们刷新到磁盘;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 状态信息
mysql> SHOW ENGINE INNODB STATUSG
----------------------
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]
参考