发现很多铁子还是不够了解Redis的过期淘汰策略
- 之前有个铁子问我,说我的redis怎么经常会丢掉一些数据,写进去了,过一会可能就没了?
- 还有个铁子说,我的key明明都过期了,怎么还占用着内存啊?
假设我设置了一批key的过期时间为1小时,1小时后redis是怎么对这批key进行删除的?
答案是:定期删除+惰性删除
所谓定期删除,指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。注意,这里可不是每隔100ms就遍历所有设置了过期时间的key而是随机检查删除。
那有些key没有被随机到没被删掉咋整?
所以就有了惰性删除。这就是说,在你获取某个key的时候,并且这个key设置了过期时间,redis会先检查一下该key是否过期,如果过期了此时会进行删除并且不给你返回任何东西。没过期的话就该怎样怎样。
所以说,redis是采用了定期删除+惰性删除的策略,并不是设置了过期时间的key一到时间就一定会被删除。他会先随机抽取进行删除,没被随机到的停留在内存中,除非你去查一下那个key,才会被redis给删除。
那如果定期删除漏掉了很多key,而且你也没有去查询走惰性删除,还是会有大量过期的key堆积在你的内存中可咋办?。
答案:走内存淘汰机制。
内存淘汰机制的意思就是:如果redis的内存占用过多的时候,为了保证新数据的成功写入,会进行数据淘汰。
有如下内存淘汰机制:
- noeviction:当内存不足以容纳新写入的数据时,写入操作会报错。
- allkeys-lru:优先删除最近最少使用的key,所有的key通用。(常用)
- allkeys-random:所有的key通过,随即删除部分key。
- volatile-lru:只限于设置了过期时间的key,并且优先删除最近最少使用的key。
- volatile-random:只限于设置了过期时间的key,随机删除部分key。
- volatile-ttl:只限于设置了过期时间的key,优先删除剩余时间最短的key。
到这我想这两位铁子应该知道问题所在了。
手撕LRU
根据我的观察,当你说到allkeys-lru这个内存淘汰机制之后,有很多面试官会让你手写一下LRU算法,考察一下你的编码功底。
虽然心里MMP,但是脸上还得笑嘻嘻。
但你可别搞原始的那个,那真TM多,写不完的。下面演示一个折中一点的。
public class LRUCache<K,V> extends LinkedHashMap<K,V> {
private final int CACHE_SIZE;
/**
* 这里就是传递进来最多能缓存多少数据
* @param cacheSize 缓存大小
*/
public LRUCache(int cacheSize){
//这块就是设置一个hashmao的初始大小,同时最后一个true指的是让linkedHashMap按照访问顺序来进行排序
//最近访问的放在头,最老访问的放在尾。
super((int)Math.ceil(cacheSize / 0.75) + 1 , 0.75f , true);
CACHE_SIZE = cacheSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest){
//这个意思就是说当map中的数据量大于指定的缓存个数的时候就自动删除最老的数据
return size() > CACHE_SIZE;
}
}