mysql中的Innodb_buffer_pool

参考文章:

《mysql底层解析——缓存,Innodb_buffer_pool,包括连接、解析、缓存、引擎、存储等》

        写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。

前言

         在之前的文章《mysql内存相关知识介绍》中,我们对mysql的内存有了初步的了解,在最后我们提及了mysql内存的重要组成部分Innodb_buffer_pool,这篇文章我们就来更深入了解下它。

目录

前言

一、Innodb_buffer_pool的内部结构

二、插入缓冲(insert buffer)与变更缓冲(change buffer)

三、数据合并(Merge buffer)

        1、写回规则

        2、redo log

四、补充

        1、淘汰算法

        2、状态查看


一、Innodb_buffer_pool的内部结构

             

        我们可以看到,Innodb_buffer_pool的组成部分包括索引、插入缓存、锁、缓存数据等。

        和操作系统类似,mysql读取数据时也采用了分页读取的方式,当发生缺页中断的时候,去磁盘上读取这个数据块,找到后把这一整个数据页都读入内存中(根据局部性原理,当某个数据被使用时,那么他相邻的数据也有较大可能被使用到)。这样的数据读取方式有效的减少的磁盘的随机读,实现了读取性能的优化。

        使用如下语句查看Innodb_buffer_pool的大小

show variables like 'innodb_buffer_pool_size'

                

        另外,我们还可以查看Innodb_buffer_pool使用内存页的情况

show global status like '%innodb_buffer_pool_pages%'

                

        Innodb_buffer_pool_pages_data:缓存池中包含数据的页的数目,包括脏页。单位是page。

        Innodb_buffer_pool_pages_dirty:缓存池中脏页的数目。单位是page。

        Innodb_buffer_pool_pages_flushed:缓存池中刷新页请求的数目。单位是page。

        Innodb_buffer_pool_pages_free:剩余的页数目。单位是page。

        Innodb_buffer_pool_pages_misc:缓存池中当前已经被用作管理用途或hash index而不能用作为普通数据页的数目。单位是page。

        Innodb_buffer_pool_pages_total:缓冲池的页总数目。单位是page。

        在数据库专用服务器中,Innodb_buffer_pool推荐的大小设置为系统内存的70%-80%(不能太小但也不能太大,小了的话内存不够用影响性能,大了的话可能导致swap分区被占用,同样影响性能)。

        索引、锁等信息大家都不陌生,这里就不展开来讲了,有兴趣的朋友可以看下我前面的

介绍《mysql之事务、锁、隔离级别与MVCC》《mysql库中索引的基础概念》

我们着重来讲下插入缓冲(insert buffer) 和 变更缓冲(change buffer)以及mysql中的相关配套措施。

二、插入缓冲(insert buffer)与变更缓冲(change buffer)

        我们都知道mysql的索引结构是基于b+树建立的,对于一颗b+树而言,每次新增1个叶子节点都会涉及非常多的步骤,包括但不限于扩容、校验、寻址等。所以当数据库进行频繁的插入时,若此多的I/O操作对于性能的影响是比较大的。

        对于主键索引,因为每次插入都是顺序增长的,所以问题不大。但是对于二级索引(非主键索引、非聚簇索引)就不是这样了,每次数据的插入都需要对这些二级索引的b+树进行维护,这个步骤需要根据自己的索引列进行排序,这就需要随机读取了。二级索引越多,那么插入就会越慢,因为要寻找的树更多了。

        于是,mysql设计了插入缓冲(insert buffer)。简单来说就是不是每次都插入到索引页中,而是先判断该索引页是否在缓冲池中,若在,就直接插入,若不在,则先插入一个insert buffer里,再以一定的规则进行真正的插入到二级索引的操作,这时就可以聚合多个操作,一起去插入。通过减少磁盘的随机读写,提高性能

        change buffer其实是对insert buffer的扩充,不仅insert会有缓存池,update、delete也存在缓存池。也就是说对于所有的DML操作,都会先进缓冲区,再根据一定的规则,写回磁盘。

        我们还可以查看并修改buffer的设置,我们可以修改为all(全部启用)、insert(仅插入启用)、none(不启用)等.

show variables like 'Innodb_change_buffering'

                ​​​​​​​        

         Innodb_change_buffer_max_size表示buffer最多占Innodb_buffer_pool百分之多少的空间。

show variables like 'Innodb_change_buffer_max_size'

        ​​​​​​​        

三、数据合并(Merge buffer)

        在上文中我们了解了mysql利用缓冲池减少了对磁盘的I/O操作,但是无论怎样,这些数据都是要写回磁盘才算DML操作的真正结束。这一节我们来介绍下写回规则与容灾措施。

        1、写回规则

        (1)insert buffer已无可用空间 

        (2)当二级缓存被读取进入内存中时

        前面我们提到了,只有当索引页不在内存中时,才会把数据临时放入到change buffer中,既然这里我们把二级索引给读取了进来,自然就可以把这个修改冲buffer中给取出并合并入二级索引中。不过需要注意的时,此时这个数据仍然在内存中,不过是从变更缓冲(change buffer)中给写回到索引页(index page)中,而不是磁盘,至于磁盘的写回则要更晚,这一点我们后面会介绍

       (3)后台线程定时写回

            mysql为了防止内存中的数据不要过大,专门设置了1个主线程master thread定期取出变更缓冲(change buffer)中的数据写回磁盘。

        2、redo log

        现在,我们知道了mysql利用缓冲池的机制实现了尽量少的磁盘读写,进而优化了数据库的性能。但是这带来了一个新的问题,内存中的数据与磁盘上的数据不一致,操作系统中的专业术语叫做脏页,如此多的脏页,万一mysql挂了、服务器宕机了,内存上没有写回磁盘的数据不久丢失了吗,这违反了数据一致性规则。

        为了解决这一问题,mysql使用redo log来记录所有的事物,当事务开始时,逐步开始写redo log,记录下每一步的操作,而后修改数据(这里的修改数据对应上文中的change buffer),最后,当脏页根据前文中提及的规则写回磁盘后,对应的redo log便可以被重新(覆盖)

        这样,即使服务器宕机,缓冲池中的数据丢失,我们也不用担心出现数据不一致的问题,mysql会去读取redo log中的日志恢复。

四、补充

        1、淘汰算法

        在操作系统中我们使用LRU(Least Recently Used最近最少使用)算法来进行页面替换,将内存中最近最少使用的页面换出内存,最频繁使用的页在LRU列表的前端,最少使用的页在LRU列表的尾端。淘汰的话,就首先释放尾端的页。在Innodb_buffer_pool中也类似,之所以说类似,是因为Innodb_buffer_pool中并不会把替换进来的页放在LRU队首,而是放在一个midpoint的位置,这个参数可以通过Innodb_old_blocks_pct来控制,默认距尾端37%的位置。

show variables like 'Innodb_old_blocks_pct'

        在midpoint之后的列表都是old列表,之前的是new列表,可以简单理解为new列表的页都是最活跃的数据。

        之所以不直接放在头部,是因为其实我们并不能确定这一页的数据是否会被多次用到,也许只是偶发性的被使用到,因此并不能确定这个页面就是最活跃的,所以放在一个较为靠近末尾的位置,避免了队首真正活跃的页面被后移。

        另外还有个参数可以控制这个参数用来表示 页读取到mid位置后,需要等待多久(单位为毫秒)才会被加入到LRU列表的。

show variables like 'Innodb_old_blocks_time'

        ​​​​​​​       

        2、状态查看

        在之前的文章《mysql死锁分析工具show engine innodb status》中有介绍过死锁分析工具,这里再介绍下这个工具的另一个用处,即查看缓冲池的使用情况,命中状况等。

        在开头,展示了以下信息

         几个比较有用的参数这里例举了下,其余的参数有兴趣的可以自行搜索。

        Pages made young:从 old 区移动到 new 区有多少个页

        Pages made not young:因为 innodb_old_blocks_time 的设置而导致页没有从 old 部分启动到 new 部分的操作。

        Buffer pool hit rate:表示缓冲池的命中率,通常这个值不应该小于95%,如果小于95%,则应该看看是不是由于全表扫描而导致 LRU 列表有污染。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值