文章目录
- 缓冲池 Buffer Pool
- 刷脏页的时机
- MySQL定时刷
- MySQL内存(buffer pool)不足的时候
- MySQL正常关闭的时候
- redo log满了的时候
- 刷脏导致的性能问题
- 控制刷脏页速度的因素
先了解下前置知识:
缓冲池 Buffer Pool
首先,对于InnoDB存储引擎来说,数据都是放在磁盘上的,存储引擎要操作数据,必须先把磁盘里面的数据加载到内存里面才可以操作。 这里就有个问题,是不是我们需要的数据多大,我们就一次从磁盘加载多少数据到内存呢?比如我要读6个字节。 磁盘I/O的读写相对于内存的操作来说是很慢的。如果我们需要的数据分散在磁盘的不同的地方,那就意味着会产生很多次的I/O操作。 所以,无论是操作系统也好,还是存储引擎也好,都有一个预读取的概念。也就是说,当磁盘上的一块数据被读取的时候,很有可能它附近的位置也会马上被读取到,这个就叫做局部性原理。那么这样,我们干脆每次多读取一点,而不是用多少读多少。 InnoDB设定了一个存储引擎从磁盘读取数据到内存的最小的单位,叫做页。操作系统也有页的概念。操作系统的页大小一般是4K,而在InnoDB里面,这个最小的单位默认是16KB大小。如果要修改这个值的大小,需要清空数据重新初始化服务。
举个例子,你去烧烤店跟老板说,老板,来一个生蚝。他根本不卖,懒得给你烤。老板卖给你生蚝,就是一打一打地卖。 我们要操作的数据就在这样的页里面,数据所在的页叫数据页。
这里有一个问题,操作数据的时候,每次都要从磁盘读取到内存(再返回给Server),有没有什么办法可以提高效率? 还是缓存的思想。把读取过的数据页缓存起来。 InnoDB设计了一个内存的缓冲区。读取数据的时候,先判断是不是在这个内存区域里面,如果是,就直接读取,然后操作,不用再次从磁盘加载。如果不是,读取后就写到这个内存的缓冲区。 这个内存区域有个专属的名字,叫 Buffer Pool。 修改数据的时候,也是先写入到 buffer pool,而不是直接写到磁盘。当数据在缓存中,也就是内存的数据页和磁盘数据不一致的时候,我们把它叫做脏页。那脏页什么时候才同步到磁盘呢? InnoDB里面有专门的后台线程把Buffer Pool的数据写入到磁盘,每隔一段时间就一次性地把多个修改写入磁盘,这个动作就叫做刷脏。
刷脏页的时机
MySQL定时刷
MySQL会在自认为系统“空闲”的时候或者当系统更新很频繁,redo log很快就写满的情况下,合理的定时进行刷脏
MySQL内存(buffer pool)不足的时候
当需要将数据页读到内存中时,发现内存不够了,就需要淘汰掉内存中最不经常使用的数据页,空出内存给别的数据页使用,如果淘汰的是“脏页”,就要先把脏页写到磁盘中。
MySQL正常关闭的时候
如果关闭的时候不刷脏,启动的时候就需要去读redo log然后同步数据到磁盘,这样启动速度会变慢。
redo log满了的时候
redo log写满的时候,整个系统就不能再接收更新了,所有的更新必须都阻塞住。这种情况要尽量避免。
刷脏导致的性能问题
一个查询要淘汰的脏页个数太多,会导致查询的相应时间明显变长 日志写满,更新全部读,写性能跌为0,这种情况对敏感业务来说,是不能接受的
因此InnoDB要控制脏页比例,来尽量避免这两种情况
需要正确告诉InnoDB所在主机的IO能力,这样InnoDB才能知道需要全力刷脏页的时候,可以刷多快。 可以通innodb_io_capacity参数来控制InnoDB的刷盘能力,这个值建议设置成磁盘的IOPS,通过fio工具可以测试出磁盘的IOPS,命令如下:
代码语言:javascript复制fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest
innodb_io_capacity的默认值为200,正确配置innodb_io_capacity可以发挥机器的性能,错误配置也会导致性能问题,比如使用SSD的硬盘就可以将这个值配大些,但是也不能配置过大,配置过大会导致InnoDB把磁盘的能力全用来刷脏页了,不能服务用户请求。
控制刷脏页速度的因素
如果刷脏页慢,会导致内存脏页太多,其次是redo log写满(因为脏页还没有同步到磁盘,redo log就不能覆写)。 InnoDB的刷盘速度就通过脏页比例和redo log写盘速度来控制的.
为了减少刷脏给业务带来的影响,要合理的设置innodb_io_capacity的值,并且平时要多关注脏页比例,不要让它经常解决75%。
代码语言:javascript复制--脏页比例计算:
select VARIABLE_VALUE into @a from performance_schema.global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty';
select VARIABLE_VALUE into @b from performance_schema.global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total';
select @a/@b;
连带机制
一旦一个查询请求需要在执行过程中刷掉一个脏页时,这个查询就可能要比平时慢了,MySQL中的一个机制可能会让查询更慢。 在准备刷一个脏页的时候,如果这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉,并且这个逻辑会继续蔓延。 通过innodb_flush_neighbors可以控制这个行为,值为1的时候会有上述的连带机制,MySQL8.0以下默认为1。
建议:
当使用的是机械硬盘时,建议开启,这样可以减少很多的随机IO 当使用的是固态硬盘这类IOPS比较高的设备时,建议关闭,因为这个时候IOPS往往不是瓶颈,这样可以减少SQL的响应时间