美文网首页Java架构技术进阶
坦白讲吧,Redis内存回收策略和key失效机制,搞不懂就别去面

坦白讲吧,Redis内存回收策略和key失效机制,搞不懂就别去面

作者: 代码小当家 | 来源:发表于2020-06-19 21:06 被阅读0次

    Redis是基于内存的key-value数据库,内存的大小是有限制的,如果内存满了,Redis会怎么办呢,另外,我们可以通过expire设置key的过期时间,那么key过期失效了, Redis回收机制又是怎么样的呢?

    内存回收策略

    最大内存配置

    Redis的按照目录下的redis.conf配置文件中可以配置redis占用内存的大小

    # 设置最大占用内存为100MB
    maxmemory 100mb
    

    tips: 如果这里设置为0的话,64位的操作系统默认是没有内存限制,而32位的操作系统隐式限制为3GB

    Redis还有两个关于最大内存的命令

    // 获取最大内存限制
    config get maxmemory
     1)  "maxmemory"
     2)  "0"
    
    // 设置最大的内存限制
    config set maxmemory 100mb
    
    

    内存驱逐策略(Eviction policies)

    当达到配置文件最大内存限制的时候,Redis有几种策略来处理这种情况:

    如果不懂LRU算法,可以参考一下这篇文章LRU算法

    • noeviction(默认策略):对于写请求不再提供服务,直接返回错误(DEL请求和部分特殊请求除外)
    • allkeys-lru:从所有key中使用LRU算法进行淘汰
    • volatile-lru:从设置了过期时间的key中使用LRU算法进行淘汰
    • allkeys-random:从所有key中随机淘汰数据
    • volatile-random:从设置了过期时间的key中随机淘汰
    • volatile-ttl:在设置了过期时间的key中,根据key的过期时间进行淘汰,越早过期的越优先被淘汰
    当使用volatile-lru、volatile-random、volatile-ttl这三种策略时,如果没有key可以被淘汰,则和noeviction一样返回错误
    

    redis 支持利用命令对驱逐策略进行修改

    // 获取内存淘汰策略 可以看到默认是noeviction
    config get maxmemory-policy
     1)  "maxmemory-policy"
     2)  "noeviction"
    
     // 修改内存驱逐策略
     config set maxmemory-policy allkeys-lru
    

    同样地,也可以在配置文件中指定驱逐策略

    maxmemory-policy allkeys-lru
    

    驱逐策略如何生效

    1. 当Redis收到一条会添加数据的命令
    2. Redis检查内存使用情况,是否超过最大内存限制
    3. 超过则执行内存驱逐策略,然后执行命令。

    tips:如果某个命令大量使用内存,则占用内存可能会超过最大内存限制


    Redis中实现的LRU算法

    Redis实现的是一个近似的LRU算法,它跟常规的LRU算法还不太一样。近似LRU算法通过随机采样法淘汰数据,每次随机出5(默认)个key,从里面淘汰掉最近最少使用的key。

    Redis为了实现近似LRU算法,给每个key增加了一个额外增加了一个24bit的字段,用来存储该key最后一次被访问的时间。

    tips:可以通过设置值maxmemory-samples参数修改采样数量

    Redis 3.0对这个近似算法的优化

    新算法会维护一个候选池(大小为16),池中的数据根据访问时间进行排序,第一次随机选取的key都会放入池中,随后每次随机选取的key只有在访问时间小于池中最小的时间才会放入池中,直到候选池被放满。当放满后,如果有新的key需要放入,则将池中最后访问时间最大(最近被访问)的移除。

    当需要淘汰时,需要从池中捞出最久没被访问的key淘汰掉就行了。

    新旧算法的对比

    下面的图片是Redis官方文档给出的新旧算法对比结果:

    image

    Redis 3.0 与 Redis 2.8 LRU内存驱逐算法对比

    • 浅灰色是被淘汰的数据
    • 灰色是没有被淘汰掉的老数据
    • 绿色是新加入的数据

    可以看到3.0的效果明显比2.8的要得多,并且取样数越大,越接近标准的LRU算法


    为什么Redis不使用真正的LRU

    原因很简单,理论的LRU需要你占用更大的内存(每个key还需要保存前后key的地址), 但你从上图就可以看出Redis 3.0使用的近似LRU算法使用起来的效果几乎与理论的LRU等效了。

    新的驱逐策略---LFU

    LFU算法是Redis4.0里面新加的一种淘汰策略。它的全称是Least Frequently Used,它的核心思想是根据key的最近被访问的频率进行淘汰,很少被访问的优先被淘汰,被访问的多的则被留下来。

    LFU算法能更好的表示一个key被访问的热度。假如你使用的是LRU算法,一个key很久没有被访问到,只刚刚是偶尔被访问了一次,那么它就被认为是热点数据,不会被淘汰,而有些key将来是很有可能被访问到的则被淘汰了。如果使用LFU算法则不会出现这种情况,因为使用一次并不会使一个key成为热点数据。

    实现主要依靠于两个参数计算器和衰减周期,计算器取值范围为0-255,访问次数越高对应的取值越高,衰减周期表示每过一定的时间,就对计算器进行减值。有如下两个参数

    // 因子越大,改要使频率计数器所需的次数越多
    lfu-log-factor 10
    // 每隔1分钟计算器减1, 如果是0的话表示每次扫描时总是使计数器衰减
    lfu-decay-time 1
    

    LFU一共有两种策略:

    • volatile-lfu:在设置了过期时间的key中使用LFU算法淘汰key
    • allkeys-lfu:在所有的key中使用LFU算法淘汰数据

    key失效机制

    redis的Key失效机制有两种:被动方式(passive way)和主动方式(active way)

    被动方式

    当客户端尝试访问key时,如果发现key已经失效了,就删除该key,并且告诉客户端该key已经失效了。

    主动方式

    当然,有被动方式还不够,因为可能会存在一些过期的key却不会被再次访问。

    那怎么删除这些key呢,定时遍历整个库吗?这样当然不行,数据量大的时候太过于耗费性能了。

    Redis主动删除失效key的策略是:随机抽取一部分的key进行校验,如果已经失效,就删除淘汰。

    具体措施

    Redis每秒执行以下操作10次:

    1. 在有过期时间的key集合中随机抽取20个key。
    2. 删除所有的过期key
    3. 如果过期的key超过25%,重新执行步骤1
    image

    作者:巽竹

    链接:https://juejin.im/post/5eeb92b06fb9a058a42d0cd0

    来源:掘金

    相关文章

      网友评论

        本文标题:坦白讲吧,Redis内存回收策略和key失效机制,搞不懂就别去面

        本文链接:https://www.haomeiwen.com/subject/fupexktx.html