其实吧,LRU也就那么回事。 (中)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 其实吧,LRU也就那么回事。 (中)

借助这个结构,我们再来分析一下上面的三个条件:

  • 1.如果每次默认从链表尾部添加元素,那么显然越靠近尾部的元素就越是最近使用的。越靠近头部的元素就是越久未使用的。
  • 2.对于某一个 key ,可以通过哈希表快速定位到链表中的节点,从而取得对应的 value。
  • 3.链表显然是支持在任意位置快速插入和删除的,修改指针就行。但是单链表无法按照索引快速访问某一个位置的元素,都是需要遍历链表的,所以这里借助哈希表,可以通过 key,快速的映射到任意一个链表节点,然后进行插入和删除。

这才是面试官想要关于 LRU 的正确答案。

但是你以为回答到这里就结束了吗?

面试官为了确认你的掌握程度,还会追问一下。

那么请问:为什么这里要用双链表呢,单链表为什么不行?

你心里一慌:我靠,这题我也背过。一时想不起来了。

image.png


所以,别只顾着背答案,得理解。

你想啊,我们是不是涉及到删除元素的操作?

那么链表删除元素除了自己本身的指针信息,还需要什么东西?

是不是还需要前驱节点的指针?

那么我们这里要求时间复杂度是O(1),所以怎么才能直接获取到前驱节点的指针?

这玩意是不是就得上双链表?

咦,你看在一波灵魂追问中,就得到了答案。

面试官的第二个问题又随之而来了:哈希表里面已经保存了 key ,那么链表中为什么还要存储 key 和 value 呢,只存入 value 不就行了?

不会也不要慌,你先分析一波。

刚刚我们说删除链表中的节点,需要借助双链表来实现O(1)。

删除了链表中的节点,然后呢?

是不是还忘记了什么东西?

是不是还有一个哈希表忘记操作了?

哈希表是不是也得进行对应的删除操作?

删除哈希表需要什么东西?

是不是需要 key,才能删除对应的 value?

这个 key 从哪里来?

是不是只能从链表中的结点里面来?

如果链表中的结点,只有 value 没有 key,那么我们就无法删除哈希表的 key。那不就完犊子了吗?

又是一波灵魂追问。

所以,你现在知道答案了吗?

另外在多说一句,有的小伙伴可能会直接回答借助 LinkedHashMap 来实现。

我觉得吧,你要是实在不知道,也可以这样说。

但是,这个回答可能是面试官最不想听到的回答了。

他会觉得你投机取巧。

但是呢,实际开发中,真正要用的时候,我们还是用的 LinkedHashMap。

你说这个事情,难受不难受。


image.png


好了,你以为到这里面试就结束了?


LRU 在 MySQL 中的应用


面试官:小伙子刚刚 LRU 回答的不错哈。要不你给我讲讲,LRU 在 MySQL 中的应用?

LRU 在 MySQL 的应用就是 Buffer Pool,也就是缓冲池。

它的目的是为了减少磁盘 IO。

缓冲池具体是干啥的,我这里就不展开说了。

你就知道它是一块连续的内存,默认大小 128M,可以进行修改。

这一块连续的内存,被划分为若干默认大小为 16KB 的页。

既然它是一个 pool,那么必然有满了的时候,怎么办?

就得移除某些页了,对吧?

那么问题就来了:移除哪些页呢?

刚刚说了,它是为了减少磁盘 IO。所以应该淘汰掉很久没有被访问过的页。

很久没有使用,这不就是 LRU 的主场吗?

但是在 MySQL 里面并不是简单的使用了 LRU 算法。

因为 MySQL 里面有一个预读功能。预读的出发点是好的,但是有可能预读到并不需要被使用的页。

这些页也被放到了链表的头部,容量不够,导致尾部元素被淘汰。

哦豁,降低命中率了,凉凉。


image.png

还有一个场景是全表扫描的 sql,有可能直接把整个缓冲池里面的缓冲页都换了一遍,影响其他查询语句在缓冲池的命中率。

那么怎么处理这种场景呢?

把 LRU 链表分为两截,一截里面放的是热数据,一截里面放的是冷数据。

打住,不能再说了。

再说就是另外一篇文章了,点到为止。

如果你不清楚,建议去学习一下哦。


LRU 在 Redis 中的应用


既然是内存淘汰算法,那么我们常用的 Redis 里面必然也有对应的实现。

Redis 的内存淘汰策略有如下几种:

  • noenviction:默认策略。不继续执行写请求(DEL 请求可以处理),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。
  • volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。没有设置过期时间的 key 不会被淘汰。
  • volatile-random:从已设置过期时间的数据集中随机选择数据淘汰。
  • volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
  • allkeys-lru:和 volatile-lru 不同的是,这个策略要淘汰的 key 对象是全体的 key 集合。
  • allkeys-random:从所有数据集中随机选择数据淘汰。

Redis 4.0 之后,还增加了两个淘汰策略。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
5月前
|
缓存 算法
LRU算法详解
LRU算法详解
90 0
|
9月前
|
存储 缓存 算法
LRU缓存替换策略及C#实现
LRU缓存替换策略及C#实现
|
9月前
|
缓存 算法 Go
一个优雅的 LRU 缓存实现
一个优雅的 LRU 缓存实现
69 0
|
NoSQL 算法 Redis
其实吧,LRU也就那么回事。 (下)
其实吧,LRU也就那么回事。 (下)
109 0
其实吧,LRU也就那么回事。 (下)
|
存储 缓存 算法
其实吧,LRU也就那么回事。 (上)
其实吧,LRU也就那么回事。 (上)
98 0
其实吧,LRU也就那么回事。 (上)
|
缓存
LRU缓存
LRU缓存
80 0
LRU缓存
|
缓存 算法 Java
LRU算法
LRU是Least Recently Used的缩写,意思就是最近最少使用,常用于页面置换的一种算法。LRU算法的提出,是基于这样一个场景:在前面几条指令中使用频繁的页面很可能在后面的几条指令中频繁使用。反过来说,已经很久没有使用的页面很可能在未来较长的一段时间内不会被用到。这个,就是著名的局部性原理。此外,LRU算法也经常被用作缓存淘汰策略。本文将基于LRU算法的思想,使用Java语言实现一个我们自己的缓存工具类
|
存储 缓存 NoSQL
LRU(Least Recently Used)
Redis是基于内存存储的key-value数据库,我们知道内存虽然快但空间小,当物理内存达到上限时,系统就会跑的很慢,这是因为swap机制会将部分内存的数据转移到swap分区中,通过与swap的交换保证系统继续运行;但是swap属于硬盘存储,速度远远比不上内存,尤其是对于Redis这种QPS非常高的服务,发生这种情况是无法接收的。(注意如果swap分区内存也满了,系统就会发生错误!)
322 0
LRU(Least Recently Used)