超级苦工
阅读 160
LRU算法及其优化策略——Mysql篇

LRU算法及其优化策略——Mysql篇.jpg

上一篇文章中,介绍了LRU算法在Redis之中的应用,本篇继续给各位道友介绍在Mysql的InnobDB引擎中,是如何使用LRU算法的。

InnoDB缓冲池

缓存池简介及内存结构

首先来介绍下InnoDB的缓冲池,缓冲池简单来说就是一块内存区域,该区域内缓存着InnoDB访问存储在磁盘的数据和索引信息。缓冲池有两个作用,一是提高了大容量读取操作的效率,二是提高了缓存管理的效率。调配缓存池参数,使得经常访问的参数能够保留在缓存池中是一个很重要的Mysql优化手段。

一个InnoDB缓存池的内存结构图如下图所示:

缓冲池.png

图源自《Mysql技术内幕:InnoDB存储引擎》

缓存池状态

我们可以通过SHOW ENGINE INNODB STATUS命令来查看缓存池在InnoDB引擎中的表现:

----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 6593445888;                       // 为缓冲池分配的总内存(字节)
Dictionary memory allocated 7687783                      // 为InnoDB数据字典分配的总内存(字节)
Buffer pool size   393208                                // 分配给缓冲池的页面总大小(页)
Free buffers       352642                                // 缓冲池空闲列表的页面总大小(页)
Database pages     40485                                 // 缓冲池LRU列表的页面总大小。(页)
Old database pages 14967                                 // 缓冲池旧LRU子列表的页面总大小(页)
Modified db pages  4                                     // 缓冲池中当前修改的页面数。
Pending reads 0                                          // 等待读入缓冲池的缓冲池页面数。
Pending writes: LRU 0, flush list 0, single page 0       // 从LRU列表的底部开始写入的缓冲池中的旧脏页数。                                                          // 检查点期间要刷新的缓冲池页面数。
                                                         // 缓冲池中暂挂的独立页面写入数。
Pages made young 5, not young 0                          // 缓冲池LRU列表中变年轻的页面总数
                                                         // 缓冲池LRU列表中未设置为年轻的页面总数
...
复制代码

完整的缓存池状态信息可以在这里找到:缓存池状态信息

缓存池的数量和大小

为了避免多个线程读写缓存池引起的并发冲突,InnoDB可以配置多个缓存池,由参数innodb_buffer_pool_instances指定,内部使用散列表进行分配和管理。

通常来说,当缓存池的大小越大,则Mysql表现的越像一个内存数据库。我们可以在启动时或者运行时通过innodb_buffer_pool_size参数动态地调整缓存池的大小,需要注意的innodb_buffer_pool_size的大小会自动的调整为InnoDB缓存池块innodb-buffer-pool-chunk-size(默认为128M)的整倍数。

为避免潜在的性能问题,缓存池大小/缓存池块大小(innodb_buffer_pool_size/ innodb_buffer_pool_chunk_size)的数量不应超过1000。

缓存池的刷新

说到缓存,必须有缓存刷新机制,即剔除缓存中的脏页(已经被修改,但是并未刷入磁盘中的数据页)。

在5.7以上的版本中,InnoDB会启动默认四个线程并发的来执行缓存池中脏页的清除。脏页的清除有两种模式:

  1. 普通模式,当缓存池中的脏页比例超过innodb_max_dirty_pages_pct_lwm(低水平线默认为25%)时,启动普通模式将脏页刷新到磁盘中。
  2. aggressively flushes(激进模式?),当缓存池中的脏页比例超过innodb_max_dirty_pages_pct(默认为75%)时,启动更快的刷新模式,尽快的将脏页刷新到磁盘当中。

缓存池的预读(Prefetching )

InnoDB的缓存池不仅是被动地缓存,而且会异步地预先从磁盘中读取数据页,有两种方式:

  • 线性:根据缓存池的访问数据的顺序来预读,当读取某一区(Extend)中的页(Page)的数据超过innodb_read_ahead_threshold时,则将该区中剩余的所有页都加载到缓存池中。

  • 随机:根据缓存池中的已有页面进行预读,而不管他们的顺序,当发现缓存池中某一区内页的数量超过了innodb_random_read_ahead,则将改区中剩余的所有页都加载到缓存池中。

缓存池LRU算法

在了解了InnoDB的缓存池概念后,我们来看看背后支持缓存池工作的算法。

当我们使用朴素的LRU算法时,会发现如果有批量的操作时,会打乱缓存数据,大大降低了缓存命中率。而在Mysql当中会有大量的预读及全表扫描的操作,为了使得真真的热数据留在内存中,InnoDB缓存池采用了一种变种的LRU算法,有些像我在这篇文章中写到的LRU-K算法。

新进入缓存池的页并不会直接进入LRU链表的头部,而是插入到距离链表尾3/8的位置(可以由innodb_old_blocks_pct参数进行配置),我们将距离链表尾3/8以上的位置称为新子列表,以下的位置称为旧子列表,数据在链表中自底而上称为变年轻,反之称为变老。下图是一个示意图:

innodb-buffer-pool-list.png

  • 变年轻

    变年轻分为两种情况,第一种是来源于用户的操作而需要读取页面,此时会直接使该页直接移至新子列表链表头部。第二种是来源于数据库内部的预读操作,则在距离插入innodb_old_blocks_time(默认为1000ms)的时间内,即使访问了该页,该页也不会别移到LRU链表的头部。

    也就是说,如果是来源于用户的操作,则最起码需要两次操作才能变年轻。而如果是预读操作,则需要加上一个等待期限。

  • 变老

    随着链表数据的替换和访问,整个列表中的数据会自然的变老。最终最老的页面会从尾部逐出。

总结

本文介绍了Mysql的InnoDB引擎的缓存池的概念,及其对于LRU算法的改造。介绍了另一种解决LRU列表被污染的解决方案。

关注下面的标签,发现更多相似文章
评论
相关推荐
mark

sdsdsdsd...

1231213213112313

123123...

优秀的Node.js第三方库推荐

axiosAxios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中 cheeriocheerio是一个nodejs实现的类似jquery核心功能的一个模块,用它可...

测试呀

广泛大使馆管道施工幅度顺丰大概岁的法国当时法国对```` 范德萨手动阀是的 范德萨士大夫是的****...

1234123412

我靠,怎么删除鸭?...

test

我们的共和国##...

test

i...

BookStack v2.6 发布,功能类似 GitBook 和看云的在线文档管理系统

程序介绍BookStack,分享知识,共享智慧!知识,因分享,传承久远! BookStack,基于 Mindoc、使用Go语言的Beego框架开发的功能类似GitBook和看云的在线文档管理系统,拥有...

联合索引在B+树上的存储结构及数据查找方式

来源: 掘金 原文: 联合索引在B+树上的存储结构及数据查找方式 能坚持别人不能坚持的,才能拥有别人未曾拥有的。 关注编程大道公众号,让我们一同坚持心中所想,一起成长!! 引言 上一篇文章《MySQL...

这是标题

正文在这里...

从0到1实现Promise

来源: SegmentFault 原文: 从0到1实现Promise 前言 Promise大家一定都不陌生了,JavaScript异步流程从最初的Callback,到Promise,到Generato...

测试标题

测试标题测试标题测试标题...

111

222大啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊...

好看

...

生产环境怎么部署呀

另外,貌似界面不支持移动端...

基于Redis的推荐系统开发

原文: 基于Redis的推荐系统开发 介绍推荐系统并不总是需要用到复杂的机器学习技术.只要手头上有足够的数据,你就可以花很少的功夫开发一个推荐系统.一个最简单的推荐系统可以只是从用户感兴趣的表中查找所...

MongoDB性能优化之准备测试数据

很多时候,我们本地的代码运行的好好的,上线后,刚开始没问题,运行一段时间后就有性能问题了,这是为什么呢? 出现这种情况,往往是本地测试数据量不够,上线后,刚开始,数据量很少,也不会有问题,运行一段时间...

MySQL性能优化之准备测试数据

很多时候,我们本地的代码运行的好好的,上线后,刚开始没问题,运行一段时间后就有性能问题了,这是为什么呢? 出现这种情况,往往是本地测试数据量不够,上线后,刚开始,数据量很少,也不会有问题,运行一段时间...

Android 使用 HTTPS

来源: 简书 原文: Android 使用 HTTPS 如果你的项目的网络框架是okhttp,那么使用https还是挺简单的,因为okhttp默认支持HTTPS。传送门 Android 使用 HTTP...

Android 适配一篇就够 - 编译版本?support?API 兼容?图片适配?

来源: 简书 原文: Android 适配一篇就够 - 编译版本?support?API 兼容?图片适配? 本文介绍 Android 不同系统及图片资源的常见适配问题。 compileSdkVersi...