内存过期策略

  首先,我们想想,假如我们自己来实现过期,有这样几种方法:

我们想到的方法

优点

缺点

给每个key都监控,一旦它的过期时间到了,立马删掉。

很及时

太费cpu了

每过一段时间,扫描所有的key,把已经过期的删掉

不那么费cpu

不及时,且key太多的情况下也会耗cpu

只有我去查这个key的时候,才去校验它是不是过期了,如果过期了我就删掉它,并且不返回

及时,不耗费cpu

虽然不耗费cpu了,但是耗费内存啊!想想我要是几年不查一些key,那得完蛋

  综上,没有完美的方法,redis使用的是上面结合的方法,叫做“定期过期+惰性过期”

redis使用的过期策略

定期随机抽取一批key,进行过期检查,如果过期则删掉。同时,正在查询的key也会校对过期时间。

  细心的同学可能看到了,redis不是对所有的key进行抽取过期检查,而是对部分key进行抽取,原因是因为如果数据比较多的话抽取所有数据是一件繁琐的工作。

  还有一个问题,由于redis是随机抽取一部分key进行过期校验的,那么就会存在一些key存在redis中一直没法淘汰掉,以至于内存有效使用率大大降低。内存淘汰策略就能够解决这个问题。

redis内存淘汰策略

  redis内存淘汰策略分为以下六种:

  1. 当内存不足时,报错 —好像没有解决上面的问题。。。
  2. 当内存不足时,随机淘汰一部分key —这不太好吧。。
  3. 当内存不足时,淘汰最近最少使用的key —这个貌似可以,但是,如果我在redis中存了一些不过期的数据,你淘汰了也不太好吧。假如你在redis中数据都是可以过期的,倒没问题
  4. 当内存不足时,从设置了过期时间的key里随机淘汰一些key —这个问题也不大,不过没啥优势啊
  5. 当内存不足时,从设置了过期时间的key里淘汰快要过期的key —这。。都要过期了,你不抽取出来,过会儿也过期了,感觉做了无用功。。
  6. 当内存不足时,从设置了过期时间的key里淘汰最近最少使用的key —这个最靠谱

  上面说的,淘汰最近最少使用的key,指的是LRU算法,LRU是Least Recently Used的缩写。那么如何手写一个LRU算法呢?

用LinkedHashMap实现LRU算法

我们可以用LinkedHashMap实现LRU算法。LinkedHashMap是一个带链表的HashMap,也就是key有顺序的HashMap,它能够把最近访问的key丢到链表一头,那么我们就可以从另一头把元素删掉来达到淘汰内存的目的,直接上代码:

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 使用linkedHashMap实现LRU算法
 *
 * @author Eren
 * @date 2020/1/10 13:23
 */
public class LRUTest {
    public static void main(String[] args) {
        LinkedHashMap<Integer, String> map = new LinkedHashMap<Integer, String>(2, 0.75F, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return size() > 2;
            }
        };
        map.put(111, "111");
        map.put(222, "222");
        map.put(66, "66");
        // {222=222, 66=66}
        System.out.println(map);
        String s = map.get(222);
        // {66=66, 222=222}
        System.out.println(map);
    }
}