Redis 键的过时删除策略及缓存淘汰策略

前言

Redis缓存淘汰策略与Redis键的过时删除策略并不彻底相同,前者是在Redis内存使用超过必定值的时候(通常这个值能够配置)使用的淘汰策略;然后者是经过按期删除+惰性删除二者结合的方式进行内存淘汰的。缓存,不是存储,没法保证之前设置的缓存绝对存在。由于缓存容量是有上限的,即便set值的时候不设置过时时间,在内存不够的时候,会根据内存淘汰策略删除一些缓存。设置过时时间的key是如何删除的?过时后会当即释放内存吗?redis

过时删除策略

  • 按期删除

Redis过时Key清理的机制对清理的频率和最大时间都有限制,在尽可能不影响正常服务的状况下,进行过时Key的清理,以达到长时间服务的性能最优。redis会把设置了过时时间的key放在单独的字典中,每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)过时key的操做。算法

具体的算法以下:数据库

  1. Redis配置项hz定义了serverCron任务的执行周期,默认为10,即CPU空闲时每秒执行10次;
  2. 每次过时key清理的时间不超过CPU时间的25%,即若hz=1,则一次清理时间最大为250ms,若hz=10,则一次清理时间最大为25ms;
  3. 清理时依次遍历全部的db;
  4. 从db中随机取20个key,判断是否过时,若过时,则逐出;
  5. 如有5个以上key过时,则重复步骤4,不然遍历下一个db;
  6. 在清理过程当中,若达到了25%CPU时间,退出清理过程;

这是一个基于几率的简单算法,基本的假设是抽出的样本可以表明整个key空间,redis持续清理过时的数据直至将要过时的key的百分比降到了25%如下。这也意味着在长期来看任何给定的时刻已通过期但仍占据着内存空间的key的量最多为每秒的写操做量除以4。缓存

  • 因为算法采用的随机取key判断是否过时的方式,故几乎不可能清理完全部的过时Key;
  • 调高hz参数能够提高清理的频率,过时key能够更及时的被删除,但hz过高会增长CPU时间的消耗,为了保证不会循环过分,致使卡顿,扫描时间上限默认不超过25ms。

根据以上原理,系统中应避免大量的key同时过时,给要过时的key设置一个随机范围。服务器

优势:经过限制删除操做的时长和频率,来减小删除操做对CPU时间的占用,处理"定时删除"的缺点,按期删除过时key,处理"惰性删除"的缺点
缺点:在内存友好方面,不如"定时删除" 在CPU时间友好方面,不如"惰性删除"
难点:合理设置删除操做的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间作一次删除),这个要根据服务器运行状况来定了dom

  • 惰性删除

过时的key并不必定会立刻删除,还会占用着内存。 当你真正查询这个key时,redis会检查一下,这个设置了过时时间的key是否过时了? 若是过时了就会删除,返回空。这就是惰性删除。ide

优势:删除操做只发生在从数据库取出key的时候发生,并且只删除当前key,因此对CPU时间的占用是比较少的,并且此时的删除是已经到了非作不可的地步(若是此时还不删除的话,咱们就会获取到了已通过期的key了)
缺点:若大量的key在超出超时时间后,好久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)性能

  • 定时删除

在设置key的过时时间的同时,为该key建立一个定时器,让定时器在key的过时时间来临时,对key进行删除。this

优势:保证内存被尽快释放
缺点:若过时key不少,删除这些key会占用不少的CPU时间,在CPU时间紧张的状况下,CPU不能把全部的时间用来作要紧的事儿,还须要去花时间删除这些key,定时器的建立耗时,若为每个设置过时时间的key建立一个定时器(将会有大量的定时器产生),性能影响严重
结论:此方法基本上没人用spa

Redis采用的过时策略

  • 惰性删除+按期删除

持久化对过时key的处理

  • RDB对过时key的处理

过时key对RDB没有任何影响

1)从内存数据库持久化数据到RDB文件,持久化key以前,会检查是否过时,过时的key不进入RDB文件

2)从RDB文件恢复数据到内存数据库,数据载入数据库以前,会对key先进行过时检查,若是过时,不导入数据库(主库状况)

  • AOF对过时key的处理

过时key对AOF没有任何影响

1)从内存数据库持久化数据到AOF文件:当key过时后,尚未被删除,此时进行执行持久化操做(该key是不会进入aof文件的,由于没有发生修改命令)当key过时后,在发生删除操做时,程序会向aof文件追加一条del命令(在未来的以aof文件恢复数据的时候该过时的键就会被删掉)

2)AOF重写:重写时,会先判断key是否过时,已过时的key不会重写到aof文件

内存淘汰策略

当redis内存超出物理内存限制时,会和磁盘产生swap,这种状况性能极差,通常是不容许的。经过设置 maxmemory 限制最大使用内存。超出限制时,根据redis提供的几种内存淘汰机制让用户本身决定如何腾出新空间以提供正常的读写服务。

  • noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键(默认策略,不建议使用)
  • allkeys-lru:加入键的时候,若是过限,首先经过LRU算法驱逐最久没有使用的键
  • volatile-lru:加入键的时候若是过限,首先从设置了过时时间的键集合中驱逐最久没有使用的键(不建议使用)
  • allkeys-random:加入键的时候若是过限,从全部key随机删除
  • volatile-random:加入键的时候若是过限,从过时键的集合中随机驱逐(不建议使用)
  • volatile-ttl:从配置了过时时间的键中驱逐立刻就要过时的键
  • volatile-lfu:从全部配置了过时时间的键中驱逐使用频率最少的键
  • allkeys-lfu:从全部键中驱逐使用频率最少的键

LRU算法实现

public class LRUCache<K,V> extends LinkedHashMap<K,V> {
    private int cacheSize;
    public LRUCache(int cacheSize){
        super(10,0.75f,true);
        //设置hashmap大小,true是让linkedhashmap按照访问顺序排序
        this.cacheSize = cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        //当map中数量大于指定缓存个数的时候,自动删除最老的数据
        return size()>cacheSize;
    }
}
相关文章
相关标签/搜索