【MySql】Buffer Pool 缓冲区补充

大家好,我是 青峯!😉

今天分享的内容是mysql 内存结构中的 Buffer Pool 。

欢迎关注,持续更新中...

进入主题,带着以下问题进一步挖掘Buffer Pool😉:

📌Buffer Pool 独有LRU算法是怎样的?

📌InnoDB 是如何保证 Buffer Pool 落盘的?

📌Buffer Pool 刷盘时机?

💡 Buffer Pool 独有LRU算法是怎样的?🔽

一般的LRU算法,也是用链表实现(链表特点是增删高效且增删时不会有大量元素在内存中移动),把最热的数据放到链头(若数据本身就在链表中,就把其移到链头),其他已有数据往后移动,如果链表满了,淘汰最后多出的元素。

对于mysql来说,上述LRU算法有两个缺点:预读失效缓存池污染。 

mysql的预读是从磁盘中读取数据页到内存时,顺带把相邻的数据页一并读取。mysql通过两个参数控制预读

  • innodb_read_ahead_threshold:默认值56,读取.ibd文件中某区连续的数据页数量超过56,就触发预读机制,把下一个相邻区的数据页读进buffer pool;
  • innodb_random_read_ahead:默认值off,如果某区连续13个页在buffer pool中,并且这些数据页频繁被访问,则就触发预读机制,把该区剩余数据页读进buffer pool;

预读有效:数据访问通常遵循集中读写原则,使用一些数据,大概率也会使用附近的数据,这就是局部性原理,说明提前加载是有效的,能有效减少磁盘IO。(实际怎样,没去考究,起码觉得是能起到一定作用的🙄)

预读失效:指数据页提前被读进缓存池,到真正访问数据时,在缓存池找不到匹配的数据。

怎么解决此问题?

mysql将LRU算法进行改良,把双向链表分成两截(新区和老区),新区占63%,老区占37%(这个比例是默认的,官方测试过才这么分配的,通过 innodb_old_blocks_pct 设置老区占比)。被预读进来的数据页 和 被第一次访问的数据页 先放在老区,等再次访问的时就移到新区链头,其余元素往后移。实际只有新区的后3/4的数据被访问才会移动到链头。

缓存池污染:指某一次读取大量数据,淘汰掉缓存池里所有的热数据。

怎么解决此问题?

在上面的基础再添加一项设定,老区中的元素想要进入新区,需满足一个条件(在默认1s内再次被访问,这个时间可以通过innodb_old_blocks_time 修改)就能加入到新区。

mysql对链表的设置

  • innodb_old_blocks_pct:默认值37,设置老区占比
  • innodb_old_blocks_time:默认值1000,设置经过多少毫秒才加入新区
  • innodb_buffer_pool_size:默认值128MB,设置缓冲区大小

综上所述,buffer pool 独有的LRU算法把双向链表按比例分为新老区,并设置时间窗口来控制热数据写入新区。

💡 InnoDB 是如何保证 Buffer Pool 落盘的?🔽

文件系统中文件一页大小是4KB (命令 getconf PAGESIZE 可查),内存一页大小16KB,因此内存要把一页文件刷到磁盘,可能要走4次磁盘IO,这还是非原子性操作。若出现OS崩溃、服务器宕机、断电等情况直接导致页数据不一致,页损坏。

怎么解决此问题?

InnoDB采用 double write 技术,在内存中开辟两块连续1MB大小的区域(double write buffer)分别能存放64页数据。当有数据要刷盘时,

  1. 先把内存页数据copy到double write buffer中;
  2. 然后把double write buffer数据分两次fsync刷入磁盘每次1MB,最终生成.dblwr文件,此操作为顺序IO,速度快;
  3. 最后把double write buffer数据刷入对应的.ibd文件中;

步骤1、2、3 能够避免上述突发情况,保证磁盘页数据不被损坏。

步骤1失败                     -》 磁盘页数据正常

步骤2失败,步骤3成功 -》 磁盘页数据正常

步骤2成功,步骤3失败 -》 磁盘页数据通过.dblwr文件恢复,页数据正常

  • Innodb_doublewrite:查看是否开启double write
  • Innodb_dblwr_pages_written:记录写入double write buffer中页的数量
  • Innodb_dblwr_writes:记录double write buffer写操作的次数

Innodb_dblwr_pages_written / Innodb_dblwr_writes = 每次写多少页,一次最多能刷盘64页。可判断写压力是否大

💡 Buffer Pool 刷盘时机?🔽

计算机先把内存 write 到内核缓存空间,等待OS 对内核缓存空间执行 fsync 操作刷入磁盘。这里分了两步,mysql认为完成第一步就当作刷盘成功了 ,只有真正完成第二步才是成功刷盘。当系统崩溃后内核缓存空间数据丢失,不可靠,而每次都 fsync 操作,效率下降,所以可靠性和性能只能权衡。

刷盘时机出现在

  • buffer pool 空间不足时(按最少访问原则)需要淘汰一些数据页,其中被淘汰的页可能是脏页(被update过的页)需要更新磁盘;
  • redo Log 写满时(留到 change buffer 再详细说);
  • mysql空闲时后台线程触发刷盘,在繁忙时也会见缝插针刷盘;
  • mysql正常关闭时刷盘;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值