lru算法实现 redis_redis面试题redis的lru算法手写lru算法

本文详细介绍了Redis的缓存淘汰策略,包括noeviction、allkeys-lru等策略,以及回收进程的工作原理。重点讨论了Redis的近似LRU算法,解释了其为节省内存而采用的随机采样和淘汰池方法。同时,文章还探讨了如何使用Java的LinkedHashMap数据结构来手动实现LRU算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

e4d6b0517a82c85572718dbcdb722058.png

一、redis的缓存淘汰策略

1、redis的缓存淘汰策略回收策略

  1. noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)

  2. allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。

  3. volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。

  4. allkeys-random: 回收随机的键使得新添加的数据有空间存放。

  5. volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。

  6. volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

一般默认是allkeys-lru

2、回收进程如何工作

理解回收进程如何工作是非常重要的:

  • 一个客户端运行了新的命令,添加了新的数据。

  • Redi检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。

  • 一个新的命令被执行,等等。

  • 所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。

  • 如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。

3、近似LRU算法

  • Redis LRU 过期算法 Redis的过期算法是基于正经LRU的变种

  • 之所以不使用正经LRU算法,是因为它需要消耗大量内存,对Redis现有数据结构有较大的改造。

  • 这种变种算法是在现有的数据结构基础上使用随机采样方法来淘汰key。

  • 他是这样操作的:

    给每个key增加一个额外的字段,这个字段占24bit,也就是最后一次被访问的时间戳。

    然后随机采样出5个key(通过maxmemory_samples来调整,采样数量越大越接近于正经的LRU算法,但是也带来了淘汰速率的问题)淘汰掉最旧的key,直到Redis占用内存小于maxmemory为止。

  • 在3.0以后增加了LRU淘汰池,第一次采样的时候会把数据放到淘汰池中,之后每次采样都会和淘汰池中的数据做比较,进一步提高了与LRU算法的近似效果。

二、如何实现lru算法

可以使用java自带的linkedhashMap数据结构来实现lru;

LinkHashMap里面的entry对象除了有map结构自带的属性外,还增加了beforeafter字段;
然后除了基本的map结构外,还有一个链表结构,链表结构就是依靠这个before和after字段来链接的。0cf9e28a0d717223df5a97e70b8f8317.png

所以map的里面的每个对象都是都是链表的其中一个成员。
当我们初始化LinkHashMap的时候,会有一个参数accessOrder,当该参数为true的时候,每次put一个key之后,就会调整链表,把key对应的entry调整到链表的头。bc10c37b0c00b066552fb79fa6f3763b.png

java代码实现

public class Lru<K,V> extends LinkedHashMap<K,V> {    Lru(int initialCapacity){        super(initialCapacity, 0.75f, true);    }    public static void main(String[] args) {        Lru lru = new Lru(10);        lru.put("1","1");        lru.put("3","3");        lru.put("2","2");        lru.put("4","4");        lru.put("5","5");        lru.put("10","10");        System.out.println(lru);    }    protected boolean removeEldestEntry(Map.Entry eldest) {        return this.size() >=5;    }}

要重写removeEldestEntry方法,用于判定删除键的时刻。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值