MySQL中的InnoDB 体系结构(中)

这是学习笔记的第 1894 篇文章


InnoDB的缓存池管理技术

在开始这部分内容之前,我们需要理清buffercache的差别,因为在数据库层面会有大量的buffercache的术语,我们在学习的时候非常容易混淆。

Buffer的本意是缓冲,cache是缓存,计算机术语里面有buffer cache, page cache,和数据库里的含义是相似的。 

计算机领域中处理磁盘IO读写的时候,基于cpumemorydisk有这样一个示意图:

640?wx_fmt=png



其中page cache是文件系统层面的缓存,数据库层面最直观的就是第一次查询数据的时候会慢一些,之后就会快得多,整个过程是把磁盘里的数据加载到这个缓存里面。 

另外一部分是buffer cache,其实指的是磁盘等块设备的缓冲,比如内存里的数据要写入磁盘文件,是一个异步的过程,而且为了防止断电丢失数据库,会按照一定的策略把数据刷新落盘。如果结合最开始的InnoDB体系结构图,其实整体要表达的含义是类似的。

怎么理解MySQL里面的缓存池管理呢,我们可以先使用show engine innodb status看一下缓冲池和内存的输出内容,按照关键字“BUFFER POOL AND MEMORY”查看,输出如下:

----------------------

BUFFER POOL AND MEMORY

----------------------

Total large memory allocated 33533460480   #innodb分配的总内存32G

Dictionary memory allocated 14596467        

Buffer pool size   1965840   #缓冲池分配的页数

Free buffers       1633878     #缓冲池空闲页数

Database pages     326446   #LRU列表中分配的数据页数,包含young sublist和old sublist

Old database pages 120340  #LRU中的old sublist部分页的数量

Modified db pages  0            #脏页的数量

Pending reads      0               #挂起读的数量

Pending writes: LRU 0, flush list 0, single page 0 #挂起写的数量

Pages made young 9, not young 0  #LRU列表中页移动到LRU首部的次数,因为该服务器在运行阶段改变没有达到innodb_old_blocks_time阀值的值,因此not young为0

0.00 youngs/s, 0.00 non-youngs/s  #表示每秒young和non-youngs这两类操作的次数


如果理解了上面的输入含义,也就基本理解了缓冲池的一些基本含义。

这里要隆重介绍下InnoDB里的LRU技术,也是在数据库的缓存设计中都会使用的算法。

LRU本质是尽可能让数据页在缓存中存在,提高访问效率,但是缓存是有限的,怎么能够减少重复的页加载频率呢,InnoDB的LRU是一种定制化的算法,首先它会有一个列表,我们叫LRU LIST,上面存放了一些数据页,这里就是Database pages     326446 ,大约是5G左右,除此之外可用的也页为:Free buffers       1633878 ,大约是25G左右,如果你比较细心,拿出笔算一下,其实会发现Free buffers +Database pages的值和Buffer pool size的大小是不相等的,其实还有其他的一些其他缓冲池的页被分配利用,比如自适应哈希索引,Lock信息等,它们的管理不是基于LRU的。


回到LRU算法,InnoDB在LRU列表中加入了参考点,也叫midpoint。传统的LRU算法当访问到的页不在缓冲区是直接将磁盘页数据调到缓冲区队列;而InnoDB并不是直接插入到缓冲区队列的队头,而是插入LRU列表的midpoint位置。这个算法称之为midpoint insertion stategy。默认配置插入到列表长度的5/8处和数学中的黄金分割(0.618)很接近,midpoint由参数innodb_old_blocks_pct控制我们来简单验算验证一下,可以看到是很接近的值:

mysql>  select 5/8,1-120340/326446 ,100-@@innodb_old_blocks_pct;

+--------+-----------------+-----------------------------+

| 5/8    | 1-120340/326446 | 100-@@innodb_old_blocks_pct |

+--------+-----------------+-----------------------------+

| 0.6250 |          0.6314 |             63 |

+--------+-----------------+-----------------------------+

midpoint之前的列表称之为new列表,也叫young sublist或者sublist of new block区域,里面的数据可以理解为热数据。

之后的列表称之为old列表也叫old sublist或者sublist of old block区域,它们的关系可以参考如下图所示。

640?wx_fmt=png



但是有了参照点怎么有效的管理呢,一些全表扫描的表如果进入sublist of new block区域,整个LRU就会是性能的瓶颈了,而且mid位置的页不是永久的这种情况也叫缓存污染。为了解决这个问题,InnoDB存储引擎引入了innodb_old_blocks_time来表示页读取到mid位置之后需要等待多久才会被加入到LRU列表的热端。可以通过设置该参数保证热点数据不轻易被刷出这个参数值默认为1000(毫秒)。


所以这个时候反过来看BUFFER POOL AND MEMORY部分的输出就不难理解了,如果你在线上环境查看InnoDB的状态输出信息,会看到有多个BUFFER POOL的输出,BUFFER POOL会从0开始,

----------------------

INDIVIDUAL BUFFER POOL INFO

----------------------

---BUFFER POOL 0

Buffer pool size   245730

Buffer pool size, bytes 0

Free buffers       204625

Database pages     40414

Old database pages 14898

Modified db pages  0

Pending reads      0


这个是通过参数 innodb_buffer_pool_instances开启了多个缓存池,把需要的数据页可以通过hash算法指向不同的缓存池里面,可以进行并行的内存读写,在高IO负载的情况下性能提升明显。



InnoDB中的脏页管理


前面熟悉了InnoDB对于LRU的管理方式之后,有些同学可能有些迷茫,说还有FLUSH LIST,FREELIST这些和LRU LIST是什么关系呢,很多同学从入门到放弃就是因为这样的而一些关联关系没搞明白。


我们在InnoDB status里面输出的内容:

Free buffers       204625

其实这个是由FREE LIST来维护的。

对于脏页的管理,InnoDB有一个专门的列表FLUSH LIST,它的大小不是无限大或者动态的,在MySQL 5.6中引入了新参数innodb_lru_scan_depth控制LRU列表中可用页数量默认值为1000,即16M,它会影响现成Page Cleaner 刷新脏页的数量,从使用率和性能来说,不是越大越好。

为什么会需要FLUSH LIST来维护脏页的数量呢,主要目的是使InnoDB尽可能保持一个较新的状态,在系统崩溃之后能够快速的恢复这个对于数据状态的记录中是通过Checkpoint LSN来维护的,我们下一小节会细说Checkpoint的技术。

而对于脏页的刷新比例,是由参数innodb_max_dirty_pages_pact来控制(默认是75而根据谷歌的压测推荐是80


这几个LIST之间的关系类似于这样的形式:

640?wx_fmt=png


其中buffer pool中的最小单位是分为三种类型

1) free page :page未被使用,此种类型page位于FREE LIST

2) clean page:page被使用,对应数据文件中的一个页面,但是页面没有被修改,此种类型page位于LRU LIST

3) dirty page:page被使用,对应数据文件中的一个页面,但是页面被修改过,此种类型page位于LRU LISTFLUSH LIST

如果要查看Page的一些状态数据,可以使用如下的命令:

mysql> show global status like '%buffer_pool_pages%';

+-----------------------------------------+------------+

| Variable_name                           | Value      |

+-----------------------------------------+------------+

| Innodb_buffer_pool_pages_data           | 254103     |

| Innodb_buffer_pool_pages_dirty          | 3340       |

| Innodb_buffer_pool_pages_flushed        | 270022533  |

| Innodb_buffer_pool_pages_free           | 7998       |

| Innodb_buffer_pool_pages_LRU_flushed    | 0          |

| Innodb_buffer_pool_pages_made_not_young | 6324461464 |

| Innodb_buffer_pool_pages_made_young     | 424446968  |

| Innodb_buffer_pool_pages_misc           | 11         |

| Innodb_buffer_pool_pages_old            | 93638      |

| Innodb_buffer_pool_pages_total          | 262112     |

+-----------------------------------------+------------+

隔几秒钟再去查看,会发现页的数量就会有很明显的变化。


其中,脏页的比率计算可以参考如下的公式:

640?wx_fmt=png

缓存池中的页就是在这三种状态中进行变换和调整,总体来说,FLUSH LIST是一种定量的管理方式,追求多快好省,而FREE LISTLRU LIST是一种动态平衡的状态,大小要远远高于FLUSH LIST.


,640?


猜你喜欢

转载自blog.csdn.net/weixin_36250635/article/details/87658617