Redis 淘汰策略

113 阅读3分钟

前几天看到读书群的群主说她读书是为了什么,她说是因为读书可以让自己见到更多高人,优秀的人想法,而自己身边很难找到很多优秀的人,和优秀的人在一起,会学习到很多,也成长的更快。其实也的确是这样,就像找男女朋友一样,很多时候就是自己身边的人,不合适或者不够优秀,人是很容易被其他人影响的,除此之外,读书也是可以提高自己的思想。

每日BB结束,今天开始说redis的数据淘汰策略

啥是数据淘汰策略呢,redis是基于内存的,单线程的,如果内存满了怎么办,过期的key什么时候回收,是不是很熟悉,想想垃圾回收,意思是这个意思,但是实现却是很大不一样

淘汰策略两种 一种是不淘汰,另一种是淘汰策略

淘汰策略又分为两种,一种是key设置过期时间的淘汰,一种key不设置过期时间的淘汰

指定淘汰策略方式

在redis.conf文件中增加指定

maxmemory-policy volatile-lru

1 key设置过期时间的淘汰:

1)volitile - ttl

这种策略是塞选出要到过期时间的数据,进行淘汰,有风险干掉热点数据

2)volitile - ramdom

这种策略是随机选一个进行淘汰,风险更大了

3)volitile - lru

这中比较讲道理,但是还挺复杂的,其中涉及到了链表,还有LinkedHashMap

他是怎么工作的呢,就是塞选出,很长时间不用的缓存值进行淘汰,听起来挺简单的,做起来并不简单。

下面就来实现一个自定义的lru算法

static class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{
    //定义缓存的容量
    private int capacity;
    private static final long serialVersionUID = 1L;
    //带参数的构造器
    LRULinkedHashMap(int capacity){
        //调用LinkedHashMap的构造器,传入以下参数
        super(16,0.75f,true);
        //传入指定的缓存最大容量
        this.capacity=capacity;
    }
    //实现LRU的关键方法,如果map里面的元素个数大于了缓存最大容量,则删除链表的顶端元素
    @Override
    public boolean removeEldestEntry(Map.Entry<K, V> eldest){
        System.out.println(eldest.getKey() + "=" + eldest.getValue());
        return size()>capacity;
    }
}
public static void main(String[] args) {
    //指定缓存最大容量为4
    Map<Integer,Integer> map=new LinkHashMapDemo.LRULinkedHashMap<>(4);
    map.put(9,3);
    map.put(7,4);
    map.put(5,9);
    map.put(3,4);
    map.put(6,6);
    map.get(7)
    //总共put了5个元素,超过了指定的缓存最大容量
    //遍历结果
    for(Iterator<Map.Entry<Integer,Integer>> it = map.entrySet().iterator(); it.hasNext();){
        System.out.println(it.next().getKey());
    }
}

这就实现了,那为什么使用linkHashMap呢,1是因为顺序,2 也是最重要的就是他的get方法不仅仅会返回值,还会将值放到链表的最下端,这样每次链表的最上端就是最先放置的值,是不是感觉遇到了对的人。

但是如果redis直接使用,会有一个问题,就是如果把缓存的值直接放进去那这个链表太大了,所以redis的处理是选择N个值放进去,然后进行lru处理

4) volitile - lfu

这个是基于lru的,基本用不到,记录每一个数据的使用次数和使用时间,如果使用次数相同,那么比较使用时间,使用时间早的会优先删除

2 key不设置过期时间的淘汰:

也是以上几个,但是数据范围改变,是从所有的数据中塞选数据

3 其实以上说的都是在内存快满的时候执行的,除此之外还有两种处理机制

内存没有满时

1)主动过期

客户端来访问时,发现key过期了,那就把他删除

2)被动过期

redis 定时清理,默认是100ms跑一次,一个范围一个范围采样烧苗过期的key,如果一个范围内过期的key25%那么继续,采样扫描知道低于25%,但是这个也存在一些问题,redis是单线程的,如果存在大范围的过期,会有阻塞主线程执行的问题

4 redis 也会通过判断内存碎片是否过多来优化内存空间