redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?

本文详细解析Redis的过期策略,包括定期删除与惰性删除的结合使用,以及在内存压力下如何通过不同内存淘汰策略保障服务稳定,如LRU、随机删除等。

1 redis的过期策略都有哪些

(1)设置过期时间

我们set key的时候,都可以给一个expire time,就是过期时间,指定这个key比如说只能存活1个小时?10分钟?这个很有用,我们自己可以指定缓存到期就失效。

如果假设你设置一个一批key只能存活1个小时,那么接下来1小时后,redis是怎么对这批key进行删除的?

答案是:定期删除+惰性删除

所谓定期删除,指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。假设redis里放了10万个key,都设置了过期时间,你每隔几百毫秒,就检查10万个key,那redis基本上就死了,cpu负载会很高的,消耗在你的检查过期key上了。注意,这里可不是每隔100ms就遍历所有的设置过期时间的key,那样就是一场性能上的灾难。实际上redis是每隔100ms随机抽取一些key来检查和删除的。

但是问题是,定期删除可能会导致很多过期key到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。

并不是key到时间就被删除掉,而是你查询这个key的时候,redis再懒惰的检查一下

通过上述两种手段结合起来,保证过期的key一定会被干掉。

很简单,就是说,你的过期key,靠定期删除没有被删除掉,还停留在内存里,占用着你的内存呢,除非你的系统去查一下那个key,才会被redis给删除掉。

但是实际上这还是有问题的,如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致redis内存块耗尽了,咋整?

答案是:走内存淘汰机制。

(2)内存淘汰

如果redis的内存占用过多的时候,此时会进行内存淘汰,有如下一些策略:

redis 10个key,现在已经满了,redis需要删除掉5个key

1个key,最近1分钟被查询了100次
1个key,最近10分钟被查询了50次
1个key,最近1个小时倍查询了1次

1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的key给干掉啊
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

一些高级别的,redis单线程模型

很简单,你写的数据太多,内存满了,或者触发了什么条件,redis lru,自动给你清理掉了一些最近很少使用的数据

(3)要不你手写一个LRU算法?

最原始的LRU算法代码量太大了,可以用简单的LinkedHashMap实现

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    
private final int CACHE_SIZE;

    // 这里就是传递进来最多能缓存多少数据
    public LRUCache(int cacheSize) {
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true); // 这块就是设置一个hashmap的初始大小,同时最后一个true指的是让linkedhashmap按照访问顺序来进行排序,最近访问的放在头,最老访问的就在尾
        CACHE_SIZE = cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > CACHE_SIZE; // 这个意思就是说当map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据
    }

}
### 三级标题:Redis淘汰策略及其适用场景 Redis内存使用达到上限时,会根据配置的淘汰策略(Eviction Policy)来决定如何处理新的写入请求。Redis提供了多种淘汰策略,适用于不同的业务场景和数据重要性需求。 #### 1. noeviction(禁止淘汰) 当内存不足时,不淘汰任何数据,而是拒绝写入新数据,返回错误。这种策略适用于不允许丢失数据的场景,但可能导致写入失败,影响系统可用性。它是Redis 3.0之后版本的默认策略[^3]。 #### 2. volatile-lru(仅淘汰设置了过期时间的数据中最近最少使用的) 从设置了过期时间的键中选择最近最少使用的数据进行淘汰。适用于缓存中数据具有时效性且希望保留未设置过期时间的数据的场景。 #### 3. volatile-ttl(优先淘汰更早过期的数据) 从设置了过期时间的键中优先淘汰剩余时间较短的数据。适用于希望优先清除即将过期的数据,从而保留更长时间有效的缓存数据。 #### 4. volatile-random(随机淘汰设置了过期时间的数据) 从设置了过期时间的键中随机选择并淘汰数据。适用于对淘汰顺序没有特别要求,仅希望释放内存空间的场景。 #### 5. allkeys-lru淘汰所有键中最近最少使用的) 无论键是否设置了过期时间,都从整个数据集中选择最近最少使用的数据进行淘汰。适用于希望尽可能保留“常用”数据,适用于缓存系统中数据访问模式具有局部性的场景。 #### 6. allkeys-random(随机淘汰所有键) 从整个数据集中随机选择数据进行淘汰。适用于淘汰策略对数据访问模式影响不大,仅需要快速释放内存的场景。 --- #### 如何根据场景选择合适的淘汰策略? - **对于缓存服务**,如果数据访问具有明显的时间局部性,推荐使用 `allkeys-lru` 或 `volatile-lru`,以保留最近频繁访问的数据,提高缓存命中率。 - **对于时效性较强的数据**,如会话缓存或临时令牌,应优先使用 `volatile-ttl` 或 `volatile-lru`,确保即将过期或长期未访问的数据优先被淘汰。 - **对于关键数据不允许丢失**的场景,如数据库缓存层,应使用 `noeviction`,避免因内存不足导致数据丢失,但需确保有足够的内存或具备扩容机制。 - **对于大规模缓存系统**,若数据访问模式较为随机,且淘汰顺序不重要,可以使用 `allkeys-random` 或 `volatile-random`,实现更均匀的内存使用和淘汰效率。 --- #### 示例:设置Redis淘汰策略 在 `redis.conf` 配置文件中,通过 `maxmemory-policy` 参数设置淘汰策略: ```bash maxmemory 100mb maxmemory-policy allkeys-lru ``` 上述配置表示当内存使用达到100MB时,采用 `allkeys-lru` 策略淘汰数据。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值