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

注:本文主要参考自《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)--字符串独有的方式

注意

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

2、两种常用的过期策略

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

  • 惰性删除

    • 含义:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。
    • 优点:删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)
    • 缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)
  • 定期删除

    • 含义:每隔一段时间执行一次删除过期key操作
    • 优点:
      通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用--处理"定时删
      定期删除过期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每秒1次做的事情:
    1.测试随机的20个keys进行相关过期检测
    2.删除所有已经过期的keys。
    3.如果有多于25%的keys过期,重复步奏1
    这是一个平凡的概率算法,基本上的假设是,我们的样本是这个密钥控件,并且我们不断重复过期检测,直到过期的keys的百分百低于25%,这意味着,在任何给定的时刻,最多会清除1/4的过期keys

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

注意:

对于定期删除,在程序中有一个全局变量current_db来记录下一个将要遍历的库,假设有16个库,我们这一次定期删除遍历了10个,那此时的current_db就是11,下一次定期删除就从第11个库开始遍历,假设current_db等于15了,那么之后遍历就再从0号库开始(此时current_db==0)

4、过期策略对RDB和AOF的影响

4.1 RDB对过期key的处理

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

4.2 AOF对过期key的处理

  • 从内存数据库持久化数据到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算法,可设置最大容量,淘汰最老的数据

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 定时删除 含义:在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key...
    早起的波徳阅读 658评论 0 1
  • 本文对Redis的过期机制简单的讲解一下讲解之前我们先抛出一个问题,我们知道很多时候服务器经常会用到redis作为...
    小陈阿飞阅读 1,279评论 0 0
  • 本文对Redis的过期机制简单的讲解一下讲解之前我们先抛出一个问题,我们知道很多时候服务器经常会用到redis作为...
    流蓝浅阅读 3,983评论 0 2
  • NOSQL类型简介键值对:会使用到一个哈希表,表中有一个特定的键和一个指针指向特定的数据,如redis,volde...
    MicoCube阅读 3,961评论 2 27
  • 城南武平算是半个贵族,不过因为经营不当,打算卖掉城里的房子,连带着还有山里的田地。 叶牧看重的就是那片山里的田地,...
    子陵的小故事阅读 172评论 0 1