redis的过期策略以及内存淘汰机制

2021-12-22 14:56:48 浏览数 (1)

注:本文主要参考自《Redis设计与实现》 https://www.cnblogs.com/xuliangxing/p/7151812.html https://www.cnblogs.com/sunsing123/p/11093038.html http://www.imooc.com/article/257065?block_id=tuijian_wz

1、设置过期时间

所谓过期,就是我们插入数据的时候设置了过期时间,一班情况下有下面两种设置g

  • expire key time(以秒为单位)--这是最常用的方式
  • setex(String key, int seconds, String value)--字符串独有的方式

具体的使用方式:查看"java企业项目开发实践"的第九章 企业项目开发--分布式缓存Redis(1)和第十章 企业项目开发--分布式缓存Redis(2)

注意

  • 除了字符串自己独有设置过期时间的方法外,其他方法都需要依靠expire方法来设置时间
  • 如果没有设置时间,那缓存就是永不过期
  • 如果设置了过期时间,之后又想让缓存永不过期,使用persist key

2、两种常用的过期策略

对于上面咱们设置了过期时间的数据,那数据到期了咱们怎么删除呢?

  • 惰性删除
    • 含义:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。
    • 优点:删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)
    • 缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)
  • 定期删除
    • 含义:每隔一段时间执行一次删除过期key操作
    • 优点: 通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用--处理"定时删 定期删除过期key--处理"惰性删除"的缺点
    • 缺点 在内存友好方面,不如"定时删除" 在CPU时间友好方面,不如"惰性删除"
    • 难点 合理设置删除操作的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间做一次删除)(这个要根据服务器运行情况来定了)

注意

  • 对于主从redis结构的从结点slave的过期key处理 slave的key不会过期,只会等待master的key过期。如果master的key过期,或者通过LRU淘汰了key,那么会发送一条模拟的del命令给slave
  • 上边所说的数据库指的是内存数据库,默认情况下每一台redis服务器有16个数据库(关于数据库的设置,看下边代码),默认使用0号数据库,所有的操作都是对0号数据库的操作,关于redis数据库的存储结构,查看 第八章 Redis数据库结构与读写原理
  • memcached只是用了惰性删除,而redis同时使用了惰性删除与定期删除,这也是二者的一个不同点(可以看做是redis优于memcached的一点)
  • 对于惰性删除而言,并不是只有获取key的时候才会检查key是否过期,在某些设置key的方法上也会检查(eg.setnx key2 value2:该方法类似于memcached的add方法,如果设置的key2已经存在,那么该方法返回false,什么都不做;如果设置的key2不存在,那么该方法设置缓存key2-value2。假设调用此方法的时候,发现redis中已经存在了key2,但是该key2已经过期了,如果此时不执行删除操作的话,setnx方法将会直接返回false,也就是说此时并没有重新设置key2-value2成功,所以对于一定要在setnx执行之前,对key2进行过期检查

3、Redis采用的过期策略

惰性删除 定期删除
  • 惰性删除流程 在进行get或setnx等操作时,先检查key是否过期, 若过期,删除key,然后执行相应操作; 若没过期,直接执行相应操作
  • 定期删除流程(简单而言,对指定个数个库的每一个库随机删除小于等于指定个数个过期key) 遍历每个数据库(就是redis.conf中配置的"database"数量,默认为16) 默认Reds每秒10次做的事情: 1.测试随机的20个keys进行相关过期检测 2.删除所有已经过期的keys。 3.如果有多于25%的keys过期,重复步奏1 这是一个平凡的概率算法,基本上的假设是,我们的样本是这个密钥控件,并且我们不断重复过期检测,直到过期的keys的百分百低于25%这意味着,在任何给定的时刻,最多会清除14的过期keys.

如果当前库中没有一个key设置了过期时间,直接执行下一个库的遍历 随机获取一个设置了过期时间的key,检查该key是否过期,如果过期,删除key 判断定期删除操作是否已经达到指定时长,若已经达到,直接退出定期删除。

注意:

对于定期删除,在程序中有一个全局变量current_db来记录下一个将要遍历的库,假设有16个库,我们这一次定期删除遍历了10个,那此时的current_db就是11,下一次定期删除就从第11个库开始遍历,假设current_db等于15了,那么之后遍历就再从0号库开始(此时current_db==0) 由于在实际中并没有操作过定期删除的时长和频率,所以这两个值的设置方式作为疑问?

4、RDB对过期key的处理

过期key对RDB没有任何影响

从内存数据库持久化数据到RDB文件 持久化key之前,会检查是否过期,过期的key不进入RDB文件 从RDB文件恢复数据到内存数据库 数据载入数据库之前,会对key先进行过期检查,如果过期,不导入数据库(主库情况)

5、AOF对过期key的处理

过期key对AOF没有任何影响

从内存数据库持久化数据到AOF文件: 当key过期后,还没有被删除,此时进行执行持久化操作(该key是不会进入aof文件的,因为没有发生修改命令) 当key过期后,在发生删除操作时,程序会向aof文件追加一条del命令(在将来的以aof文件恢复数据的时候该过期的键就会被删掉) AOF重写 重写时,会先判断key是否过期,已过期的key不会重写到aof文件

5. redis内存淘汰机制

内存淘汰机制 Redis 的内存占用会越来越高。Redis 为了限制最大使用内存,提供了 redis.conf 中的配置参数 maxmemory。

当内存超出 maxmemory,Redis 提供了几种内存淘汰机制让用户选择,配置 maxmemory-policy:

  • noeviction:当内存超出 maxmemory,写入请求会报错,但是删除和读请求可以继续。(不推荐,使用这个策略,疯了吧)
  • allkeys-lru:当内存超出 maxmemory,所有的 key 中,移除最少使用的key。只把 Redis 既当缓存是使用这种策略。(推荐)。
  • allkeys-random:当内存超出 maxmemory,所有的 key中,随机移除某个 key。(应该没人用吧)
  • volatile-lru:当内存超出 maxmemory,设置了过期时间 key的字典中,移除最少使用的 key。把 Redis 既当缓存,又做持久化的时候使用这种策略。
  • volatile-random:当内存超出 maxmemory,在设置了过期时间 key的字典中,随机移除某个key。
  • volatile-ttl:当内存超出 maxmemory,在设置了过期时间 key 的字典中,优先移除 ttl 小的,也就是移除马上就要过期的key。

redis 中的默认的过期策略是volatile-lru 。设置方式 可以通过命令直接设置 config set maxmemory-policy xxxx(eg:volatile-lru)

6.LRU 算法

实现 LRU 算法除了需要 key/value 字典外,还需要附加一个链表,链表中的元素按照一定的顺序进行排列。当空间满的时候,会踢掉链表尾部的元素。当字典的某个元素被访问时,它在链表中的位置会被移动到表头。所以链表的元素排列顺序就是元素最近被访问的时间顺序。

这里基于linkhashmap实现一个lru算法,可设置最大容量,淘汰最老的数据

代码语言:javascript复制
class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private final int CACHE_SIZE;

    public LRUCache(int size) {
        //true代表顺序存放,最新的放头部,最老的放尾部
        super((int) Math.ceil(size / 0.75)   1, 0.75f, true);
        CACHE_SIZE = size;
    }

    /**
     * 定义移除最老的数据的规则
     *
     * @author zyh
     * @date 2021/8/4
     **/
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > CACHE_SIZE;
    }


}
```t

0 人点赞