redis 过期删除策略和内存淘汰机制是什么_redis缓存过期策略

redis 过期删除策略和内存淘汰机制是什么_redis缓存过期策略Redis 设置过期时间 Redis 有四个不同的命令可以用于设置键的生存时间(键可以存在多久)或过期时间(键什么时候会被删除): EXPIRE <key> <ttl> ——将

Redis 过期删除策略和内存淘汰机制

 
 
 

Redis 设置过期时间

Redis 有四个不同的命令可以用于设置键的生存时间(键可以存在多久)或过期时间(键什么时候会被删除):
  • EXPIRE <key> <ttl> ——将键 key 的生存时间设置为 ttl 秒。
  • PEXPIRE <key> <ttl>——将键 key 的生存时间设置为 ttl 毫秒。
  • EXPIREAT <key> <timestamp>——将键 key 的过期时间设置为 timestamp 所指定的秒数时间戳。
  • PEXPIREAT <key> <timestamp>——将键 key 的过期时间设置为 timestamp 所指定的毫秒数时间戳。
虽然有多种不同单位和不同形式的设置命令,但实际上 EXPIRE 、PEXPIRE 、EXPIREAT 三个命令都是使用 PEXPIREAT 命令来实现的:无论客户端执行的是四个命令中的哪一个,经过转换之后,最终的执行效果都和执行 PEXPIREAT 命令一样。
 

 

Redis 计算并返回剩余时间

Redis 提供了两个命令,其中 TTL 命令以秒为单位返回键的剩余生存时间;PTTL 命令则以毫秒为单位返回键的剩余生存时间。TTL 和 PTTL 两个命令都是通过计算键的过期时间和当前时间之间的差来实现的。
 
 

 

Redis 过期字典

redisDb 结构的 expires 字典保存了数据库中所有键的过期时间,我们称这个字典为过期字典:
  • 过期字典的键是一个指针,这个指针指向键空间的某个键对象(也即是某个数据库键)。
  • 过期字典的值是一个 long long 类型的整数,这个整数保存了键所指向的数据库键的过期时间——一个毫秒精度的 UNIX 时间戳。
 
 

 

Redis 过期键的判定

通过过期字典,程序可以用以下步骤检查一个给定键是否过期:
  1. 检查给定键是否存在于过期字典,如果存在,那么取得键的过期时间。
  2. 检查当前 UNIX 时间戳是否大于键的过期时间,如果是的话,那么键已经过期,否则的话,键未过期。
 
 

 

三种过期键删除策略

定时删除

在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作。

优点:

  • 对内存是最友好的。通过使用定时器,定时删除策略可以保证过期键会尽可能快地被删除,并释放过期键所占用地内存。

缺点:

  • 对 CPU 时间是最不友好的。在过期键比较多的情况下,删除过期键这一行为可能会占用相当一部分 CPU 时间,在内存不紧张但是 CPU 时间非常紧张的情况下,将 CPU 时间用在删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响。
  • 创建一个定时器需要用到 Redis 服务器中的时间事件,而当前时间事件的实现方式是无序链表,查找一个事件的时间复杂度为 O(N),这并不能高效地处理大量时间事件。
 

惰性删除

放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。

优点:

  • 对 CPU 时间来说是最友好的。程序只会在取出键时才对键进行过期检查,这可以保证删除过期键的操作只会在非做不可的情况下进行,并且删除的目标仅限于当前处理的键,这个策略不会在删除其他无关的过期键上花费任何 CPU 时间。

缺点:

  • 对内存是最不友好的。如果一个键已经过期,而这个键又仍然保留在数据库中,那么只要这个过期键不被删除,它所占用的内存就不会释放。如果数据库中有非常多的过期键,而这些过期键又恰好没有被访问到的话,那么它们也许永远也不会被删除(除非用户手动执行 FLUSHDB),我们甚至可以将这种情况看作是一种内存泄露,无用的垃圾数据占用了大量内存,而服务器却不会自己去释放它们。
 

定期删除

每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。

优点:

  • 之前讨论的两种删除策略都有明显的缺陷,定期删除策略是前两种策略的一种整合和折中。
  • 定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。
  • 除此以外,通过定期删除过期键,定期删除策略有效地减少了因为过期键而带来的内存浪费。

缺点:

  • 定期删除的难点是确定删除操作执行的时长和频率。
  • 如果删除操作执行得太频繁,或者执行的时间太长,定期删除策略就会退化成定时删除策略,以至于将 CPU 时间过多地消耗在删除过期键上面。
  • 如果删除操作执行得太少,或者执行的时间太短,定期删除策略又会和惰性删除策略一样,出现浪费内存的情况。
 
 

 

Redis 的过期删除策略

前面讨论了定时删除、惰性删除和定期删除三种过期键删除策略,
Redis 服务器实际使用的是惰性删除和定期删除两种策略。通过配合使用这两种策略,服务器可以很好地在合理使用 CPU 时间和避免浪费内存空间之间取得平衡。
 

惰性删除策略的实现

过期键的惰性删除策略由 db.c/expireIfNeeded 函数实现,所有读写数据库的 Redis 命令在执行之前都会调用 expireIfNeeded 函数对输入键进行检查:
  1. 如果输入键已经过期,那么 expireIfNeeded 函数将输入键从数据库中删除。
  2. 如果输入键未过期,那么 expireIfNeeded 函数不做动作。
 

定期删除策略的实现

过期键的定期删除策略由 redis.c/activeExpireCycle 函数实现,每当 Redis 的服务器周期性操作 redis.c/serverCron 函数执行时,activeExpireCycle 函数就会调用,它在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的 expires 字典中随机检查一部分键的过期时间,并删除其中的过期键。
Redis 默认每秒进行 10 次过期扫描(Redis 的配置文件里面的 hz 参数配置),过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略,步骤如下:
  1. 从过期字典中随机选出 20 个 key。
  2. 删除这 20 个 key 中已经过期的 key。
  3. 如果过期的 key 的比例超过 1/4,那就重复步骤(1)。
同时,为了保证过期扫描不会出现循环过度,导致线程卡死的现象,算法还增加了扫描时间的上限,默认不会超过 25ms。
 
 
 

 

Redis 的内存淘汰机制

为了限制最大使用内存,Redis 提供了配置参数
maxmemory 来限制内存超出期望大小。
当实际内存超出 maxmemory 时,Redis 提供了几种可选策略(
maxmemory-policy)来让用户自己决定该如何腾出新的空间以继续提供读写服务。
  • noeviction:不会继续服务写请求(del 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。
  • volatile-lru:尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。
  • volatile-ttl:跟上面几乎一样,不过淘汰的策略不是 LRU,而是比较 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
  • volatile-random:跟上面几乎一样,不过淘汰的 key 是过期 key 集合中随机的 key。
  • alllkeys-lru:区别于 volatille-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合,这意味着一些没有设置过期时间的 key 也会被淘汰。
  • alllkeys-random:跟上面几乎一样,不过淘汰的 key 是随机的 key。
 
volatile-xxx 策略只会针对带过期时间的 key 进行淘汰,allkeys-xxx 策略会对所有的 key 进行淘汰。如果你只是拿 Redis 做缓存,那么应该使用 allkeys-xxx 策略,客户端写缓存时不必携带过期时间。如果你还想同时使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key,不会被 LRU 算法淘汰。
 
 
 

 

Redis 的 LRU 算法

  Redis 使用的是一种近似 LRU 算法。之所以不使用 LRU 算法,是因为其需要消耗大量的额外内存,需要对现有的数据结构进行较大的改造。近似 LRU 算法很简单,在现有数据结构的基础上使用随机采样法来淘汰元素,能达到和 LRU 算法非常近似的效果。
  当 Redis 执行写操作时,发现内存超出 maxmemory,就会执行一次 LRU 淘汰算法。这个算法也很简单,就是随机采样出 5 个 key(数量可以配置,maxmemory_samples),然后淘汰掉最旧的 key,如果淘汰后内存还是超出 maxmemory,那就继续随机采样淘汰,直到内存低于 maxmemory 为止。
如何采样要看 maxmemory-policy 的设置,如果是 allkeys,就从所有的 key 字典中随机采样,如果是 volatile,就从带过期时间的 key 字典中随机采样。每次采样多少个 key 取决于 maxmemory_samples 的设置,默认为 5。
  Redis 3.0 在算法中增加了淘汰池,进一步提升了近似 LRU 算法的效果。淘汰池是一个数组,它的大小是 maxmemory_samples,在每一次淘汰循环中,新的随机得出的 key 列表会和淘汰池中的 key 列表进行融合,淘汰掉最旧的一个 key 之后,保留剩余较旧的 key 列表放入淘汰池中留待下一个循环。

 
 
 
 
 
 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/5808.html

(0)
上一篇 2023-04-23
下一篇 2023-04-24

相关推荐

  • 如何安装Tesseract

    如何安装TesseractTesseract是一个由HP实验室开发的免费OCR引擎。它最初发布于1985年,但直到2005年才成为开源软件。自那时以来,Tesseract已经成长为一款功能强大的OCR引擎,并且已被许多人在各种应用程序中使用。

    2024-08-28
    24
  • 成功安装python,成功安装jieba库但调用不了[亲测有效]

    成功安装python,成功安装jieba库但调用不了[亲测有效]在Python官网下载Python安装包,双击打开Python软件。勾选add Python 3.8 to PATH,点击install Now。安装完成后,点击Close.打开电脑命令提示符,输入Python,按回车键运行。出现版本号,就说明安装成功。

    2023-08-25
    141
  • MapReduce切片机制及执行流程[亲测有效]

    MapReduce切片机制及执行流程[亲测有效]MapReduce的切片机制 在Map阶段会将读取进来的数据进行逻辑切片进行处理。此切片与HDFS的切块不同,HDFS的切块是将文件按照block块的形式保存起来,mr则是将文件按照切片数进行计算默认

    2023-05-08
    154
  • 使用Python Gensim实现主题建模:简单有效的文本分析技术

    使用Python Gensim实现主题建模:简单有效的文本分析技术在信息时代,大量的文本数据涌入我们的视野。如何从海量文本中提取出有用的信息,对于企业和个人都是非常重要的。而主题建模是一种有效的文本分析技术,可以帮助我们发掘文本的潜在主题,进而进行分析和挖掘。

    2024-07-03
    42
  • 数据库发展史(下)

    数据库发展史(下)本篇文章为大家讲解AI原生数据库和其他类型数据库的发展历程。 AI原生数据库 近年来,随着AI(人工智能)技术的成熟和发展,AI与数据库的结合越来越紧密。为了提高数据库系统的智能化程度,使数据库系统…

    2023-04-12
    163
  • 自己动手制作MySQL Internals Manual For Dash文档[亲测有效]

    自己动手制作MySQL Internals Manual For Dash文档[亲测有效]老实说,我刚用Dash没几天,感觉还不错,毕竟有份本地化文档还是比较方便,不用总实时打开MySQL官档网页。不过,目前Dash只有MySQL 5.5 ~ 8.0的官档,没有其他相关文档,有时候想查看…

    2023-02-14
    153
  • 中国最好的免费公开课网站_公开课收费吗

    中国最好的免费公开课网站_公开课收费吗第十六期、Postgresql 冷冻TXIDS内核剖析 1、TXIDS使用规则概述 2、为什么要冻结TXIDS 3、冻结模式触发机制 4、冻结机制对于可见性规则、CLOGs的影响 TXIDS冷冻机制…

    2023-03-17
    152
  • 数据传输 | dtle 之 job 实现简析

    数据传输 | dtle 之 job 实现简析作者:吕海龙 爱可生 DTLE 团队成员,负责 DTLE 开发 ,日常问题处理以及相关问题的排查。 本文来源:原创投稿 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。 …

    2023-02-09
    143

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注