ITPub博客

首页 > 应用开发 > Java > Redis 缓存有哪些淘汰策略?

Redis 缓存有哪些淘汰策略?

原创 Java 作者:写BUG的程序袁 时间:2021-08-20 19:51:03 0 删除 编辑

 在Redis中,内存的大小是有限的,所以为了防止内存饱和,需要实现某种键淘汰策略。主要有两种方法,一种是当Redis内存不足时所采用的内存释放策略。另一种是对过期key进行删除的策略,也可以在某种程度上释放内存。

Redis采用的默认内存释放策略是noeviction-不删除,达到最大内存时,如需更多内存(存入数据),则操作报错;默认的过期key删除策略则是惰性删除+定期删除的方案;

1 Redis内存淘汰策略

Redis的maxmemory参数用于指定 Redis 能使用的最大内存,既可以在 redis.conf 配置文件中设置(单位Byte),也可以在运行过程中通过 CONFIG SET 命令动态修改。

将 maxmemory 设置为0,或者没有设置该参数,则表示不进行内存限制。但对32位系统来说有一个隐性的限制条件是最多使用 3GB 内存,64位系统则无限制。

当达到内存限制时(maxmemory),Redis 将尝试根据选择的淘汰策略删除一部分key。淘汰可以在redis.conf中配置maxmemory-policy属性,或者通过config set maxmemory-policy命令动态的配置。

Redis的默认策略为noeviction,支持的策略有8种:

策略 描述
volatile-lru 只对设置了expire过期时间的key生效,优先删除最近最少使用(least recently used ,LRU) 的 key,直到有可用的内存,如果没有可删除的key并且内尺还是不够,则报错。
allkeys-lru 所有key通用;优先删除最近最少使用(least recently used ,LRU)的key,直到有可用的内存,如果没有可删除的key并且内尺还是不够,则报错。
volatile-lfu Redis4.0新增的策略。只对设置了expire过期时间的key生效,优先删除最不常用(least frequently used ,LFU) 的 key,直到有可用的内存,如果没有可删除的key并且内尺还是不够,则报错。
allkeys-lfu Redis4.0新增的策略。所有key通用;优先删除最不常用(least frequently used , LFU)的key,直到有可用的内存,如果没有可删除的key并且内尺还是不够,则报错。
volatile-random 只对设置了expire过期时间的key生效,随机删除一部分key,直到有可用的内存,如果没有可删除的key并且内尺还是不够,则报错。
allkeys-random 所有key通用,随机删除一部分key,直到有可用的内存,如果没有可删除的key并且内尺还是不够,则报错。
volatile-ttl 只对设置了expire过期时间的key生效,优先删除剩余时间(time to live,TTL) 最短的key,直到有可用的内存,如果没有可删除的key并且内尺还是不够,则报错。
noeviction 默认策略,不删除任何key,在进行写操作时返回错误信息

LRU (Least recently used) 最近最少使用,如果数据最近被访问过,那么将来被访问的几率也更高,也就不会被淘汰。也就是优先淘汰最长时间未被使用的数据,这个主要针对的是访问时间,可能存在某些key值在前一段时间访问很频繁,但是最近没被访问,从而被 LRU 算法删除。Java中可以通过继承LinkedHashMap快速实现一个LUR Cache,此前我们学习过了。

LFU (Least frequently used) 最不经常使用,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小,就会被淘汰。也就是优先淘汰一定时期内被访问次数最少的数据,这个主要针对的是访问频率,可能存在某些 key 值在前一段时间访问很频繁,但是最近一段时间访问比较少,从而被 LRU 算法删除。

2 Redis过期key删除策略

常见的过期数据删除策略如下:

  1. 定时删除

    1. 在设置key的过期时间的同时,创建一个定时器,让定时器在key的过期时间来临时,立即执行对key的删除操作;
    2. 定时删除操作对于内存来说是友好的,内存不需要操作,而是通过使用定时器,可以保证尽快的将过期key删除,但是对于CPU来说不是友好的,如果过期key比较多的话,起的定时器也会比较多,每一个定时器会占用到CPU的资源;

  2. 惰性删除

    1. 不管key有没有过期都不主动删除,但是每次从键空间中获取键值时,都检查取得的key的过期时间,如果过期的话,返回null,然后删除key即可;
    2. 惰性操作对于CPU来说是友好的,过期key只有在程序读取时判断是否过期才删除掉,而且也只会删除这一个过期键,但是对于内存来说是不友好的,如果多个key都已经过期了,而这些key又恰好没有被访问,那么这部分的内存就都不会被释放出来;

  3. 定期删除

    1. 每隔一段时间,程序就对数据库进行一次检查,删除掉过期key;
    2. 定期删除是上面两种方案的折中方案,每隔一段时间来删除过期key,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响,除此之外,还有效的减少内存的浪费;但是该策略的难点在于间隔时长,这个需要根据自身业务情况来进行设置,并且可能由于扫描不及时,导致过期的key也被返回。

目前,Redis采用的是惰性删除+定期删除的方案;Redis 的定期扫描只会扫描设置了过期时间的键,Redis 通过一个单独的过期字典expires(可以看作是 hash 表)来保存设置了过期时间的数据过期的时间,所以不会出现扫描所有键的情况,即使如此,redis也是默认是每隔 100ms 就随机抽取过期字典中的 key,检查其是否过期,如果过期就删除。如果不定时随机抽查而是全部扫描,那么将可能有很长的时间导致服务对外不可用,这是无异于一场灾难。

由于是随机扫描,那么对于已经过期但没有被扫描到的key怎么办呢,没关系,还有惰性删除,在获取某个 key 的时候,Redis 会检查一下 ,这个 key 如果设置了过期时间那么是否过期了?如果过期了此时就会删除,返回null。

过期字典dict的key是一个指针,这个指针指向键空间中的某个key对象(也即是某个数据库键)。过期字典的值是一个long long类型的整数,这个整数保存了key所指向的数据库key的过期时间——一个毫秒精度的UNIX时间戳。在实际中,键空间的key和过期字典的key都指向同一个key对象,所以不会出现任何重复对象,也不会浪费任何空间。

typedef struct redisDb {
    dict *dict; //键空间,存放所有的key-value键值对
    dict *expires; //设置了过期时间的key到它的过期时间的键值对
} redisDb;

PERSIST命令在过期字典中查找给定的key,并解除key和值(过期时间)在过期字典中的关联。

 最后

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

不用多说,相信大家都有一个共识:无论什么行业,最牛逼的人肯定是站在金字塔端的人。所以,想做一个牛逼的程序员,那么就要让自己站的更高,成为技术大牛并不是一朝一夕的事情,需要时间的沉淀和技术的积累。

现在竞争这么激烈,只有通过不断学习,提高自己,才能保持竞争力。

对于一些不知道学习什么,没有一个系统路线的程序员,这里给大家提供一些学习资料

需要的小伙伴,可以一键三连, 点击这里获取免费领取方式!

《Java核心知识点合集(283页)》

内容涵盖:Java基础、JVM、高并发、多线程、分布式、设计模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、数据库、云计算等 在这里插入图片描述

《Java中高级核心知识点合集(524页)》

在这里插入图片描述

《Java高级架构知识点整理》

在这里插入图片描述

《Docker从入门到实践》

在这里插入图片描述

《spring could 学习笔记》

在这里插入图片描述

《JVM与性能调优知识点整理》

在这里插入图片描述

《MySQL性能调优与架构设计解析文档》305页

在这里插入图片描述

《Nginx入门到实战》319页

在这里插入图片描述

《Java并发编程》385页

在这里插入图片描述

《1000道 互联网Java工程师面试题 (485页)》

在这里插入图片描述

需要的小伙伴,可以一键三连, 点击这里获取免费领取方式! 


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70000438/viewspace-2788091/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-05-27

  • 博文量
    50
  • 访问量
    39395