关于java:redis过期策略定期删除惰性删除

51次阅读

共计 1651 个字符,预计需要花费 5 分钟才能阅读完成。

1. 问题引入

常见的问题:

  • 往 redis 写入的数据怎么没了?
    可能有些人会问到,刚写进 redis 的数据怎么一会就没了。
    这就是对 redis 了解不透彻了,redis 是缓存,不能当存储用
    用内存当缓存,内存是无限的
    redis 次要是基于内存来进行高性能、高并发的读写操作的。
    既然内存是无限的,比方 redis 就只能用 10G,你要是往里面写 20G 的数据,会咋办?
    当然会干掉 10G 的数据,而后就保留 10G 的数据了。
    那干掉哪些数据?保留哪些数据?
    当然是干掉不罕用的数据,保留罕用的数据了。
  • 数据明明过期了,怎么还占用着内存?
    这是由 redis 的过期策略来决定的

2.redis 过期策略

    redis 过期策略是:定期删除 + 惰性删除。

所谓定期删除,指的是 redis 默认是每隔 100ms 就随机抽取一些设置了过期工夫的 key,查看其是否过期,如果过期就删除。

假如 redis 里放了 10w 个 key,都设置了过期工夫,你每隔几百毫秒,就查看 10w 个 key,那 redis 基本上就死了,cpu 负载会很高的,耗费在你的查看过期 key 上了。留神,这里可不是每隔 100ms 就遍历所有的设置过期工夫的 key,那样就是一场性能上的劫难。实际上 redis 是每隔 100ms 随机抽取一些 key 来检查和删除的。

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

获取 key 的时候,如果此时 key 曾经过期,就删除,不会返回任何货色。

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

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

3. 内存淘汰机制

redis 内存淘汰机制有以下几个:

noeviction: 当内存不足以包容新写入数据时,新写入操作会报错。(没人用,恶心)allkeys-lru:当内存不足以包容新写入数据时,在键空间中,移除最近起码应用的 key(这个是最罕用的)。allkeys-random:当内存不足以包容新写入数据时,在键空间中,随机移除某个 key,这个个别没人用吧,为啥要随机,必定是把最近起码应用的 key 给干掉啊。volatile-lru:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,移除最近起码应用的 key(这个个别不太适合)。volatile-random:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,随机移除某个 key。volatile-ttl:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,有更早过期工夫的 key 优先移除。

4. 手写一个 LRU 算法

你能够现场手写最原始的 LRU 算法,那个代码量太大了,仿佛不太事实。

不求本人纯手工从底层开始打造出本人的 LRU,然而起码要晓得如何利用已有的 JDK 数据结构实现一个 Java 版的 LRU。

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

/**
 * 传递进来最多能缓存多少数据
 *
 * @param cacheSize 缓存大小
 */
public LRUCache(int cacheSize) {
    // true 示意让 linkedHashMap 依照拜访程序来进行排序,最近拜访的放在头部,最老拜访的放在尾部。super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
    CACHE_SIZE = cacheSize;
  }

@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
    // 当 map 中的数据量大于指定的缓存个数的时候,就主动删除最老的数据。return size() > CACHE_SIZE;}
}

正文完
 0