视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Redis删除策略和逐出策略
2020-11-09 06:51:27 责编:小采
文档


前言

?

咔咔整理了一个路线图,打造一份面试宝典,准备按照这样的路线图进行编写文章,后期发现没有补充到的知识点在进行添加。也期待各位伙伴一起来帮助补充一下。评论区见哦!

?
在这里插入图片描述

过期数据

先来看三个key值,分别为sex、name、age。

这三个值设置的指令为 set name kaka setex age 100 24 setex sex 10 1

在redis中我们可以使用ttl来获取某个key的状态,下面我们来使用ttl分别获取一下上边name、age、sex的状态

可以看到出来了三个值,分别为 -1 775 -2

那么这三个值给出的信息是什么呢!

  • -1 表示永久有效的数据
  • 775 这个值是设置在age上,使用的指令为setex age 1000 24,表示为剩余有效时间
  • -2 表示已经过期的数据,或者是被删除的数据,或者说是么有定义的数据
  • 过期数据的存储结构

  • 当我们设置一个带有时效性的name时,redis存储的是一个内存地址0x10101
  • 然后redis会再开辟一个空间用来存储带有时效性的key
  • 但是存储方式是key对应的内存地址 和 过期时间那么今天我们所说的redis删除策略,就是删除的这部分数据。
  • 定时删除

    定时删除就是写一个定时器,然后当key的时间过期后,定时器任务立即对过期的key进行删除

    优点:可想而知key到期就删,肯定对内存时最友好的,节约内存

    缺点:redis单线程的特性是所有的命令都在按照一定的顺序进行执行。key值到期就删cpu的压力就会变大,会直接影响到redis服务器响应时间和IO

    定时删除就是用时间来换取空间

    当执行完定时删除后,key值对应的数据会被删除,同时在过期的内存区里边也会直接删除。

    惰性删除

    在来看这个图当key值过期后不会直接删除,那是什么时候删除呢!继续往下看

    当我们使用惰性删除时,数据到期了也不会自动删除,那么他的删除方式是,在下一次在获取这个key值时,会做一个判断,判断这个key是否过期,如果过期了在执行删除。

    也就是说当再次执行get name时 会走一个函数expirelfNeeded() 这个函数就是判断此key是否过期的。过期的返回nil,然后从内存在进行删除

    优点:会减少一定的CPU性能,只有到必须要删的时候才会删除

    缺点:那肯定就是内存压力大了,例如一些热点新闻,热点过了就基本没人访问了,没有人访问这个key就一直存在,就会出现长期占用一定的内存空间

    也就说这种方式是用空间换时间

    定期删除

    在上文中我们提及了俩种删除方式,一种是定时删除,一种是惰性删除。一个是用空间换时间。一个是用时间换空间。俩种方案都是比较极端的方式。那么接下来我们在来看看定期删除的实现方案。

    先来看一下redis的存储空间,一共有默认为16个,在redis.conf里边有一个配置参数database这个参数控制的。每个数据库都有自己的过期分区,里边存储就是数据地址 和 数据过期时间。

    实现方式

    redis在启动时,会取读取server下的hz的值,默认为10。这个值直接在终端使用info server就可以查看的到

    然后会每秒钟执行server下hz次 进行serverCron()轮询

    继续使用databasesCron对redis的16个库进行挨个访问信息

    访问时候会再执行activeExpireCycel对每个expires[*]逐一进行检测,每个执行的时间为250ms / server hz这个参数

    在对每个expirs[*]逐一检测时,会随机拿出ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC个可以进行检测

  • 如果key超时,直接删除key
  • 一轮中删除的key数量>ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC*25%继续循环该过程
  • 如果一轮中删除的key数量<=ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC25% ,检查下一个expires[]
  • 那么现在问题来了,我们的250ms / hz这个时间执行完了,但是把expires的16个数据库没有循环完怎么办呢! 下次来在循环那个库呢! 其实这个值是有存的,就是current_db这个值。这个值会记录activeExpireCycel 下次进入那个expires[*]执行特点1:CPU使用没有高峰值,检测频率自定义设置

    特点2:内存压力不会很大, 长时间占用的内存会被持续的清理

    逐出算法

    在上文中我们说了三种删除策略,但是这三种策略都是相对于设置了有效期的key才会有效。

    那现在我们的redis使用的内存不足了,就会使用逐出策略来保证redis的正常使用。

    redis在每次执行命令前会调用freeMemorylfNeeded()检测内存是否充足,当不充足时就会清理一些key,这种清除数据的策略称为逐出策略。

    redis最大可使用内存的参数为:maxmemory 默认为0 指的是占用物理内存的比例 一般设置50%就可以了

    每次选取待删除key的个数:maxmemory-samples

    删除策略:maxmemory-policy

    「下面我们来着重说明删除策略」

  • 检测易失数据(也就是我们设置了有效期,但是还没有到期的数据,就是上文expires[*])
  • volatile-lru:挑选最近少使用的数据
  • volatile-lfu:挑选最近使用次数最少的数据
  • volatile-ttl:挑选将要淘汰的数据
  • volatile-random:随机选择
  • 接下来看一幅图

  • 9s就是现在的时间

  • 距离9s最长的一个key就是age

  • 使用次数最少的就是gender这个key

  • 如果按照volatile-lru就会把age删除掉

  • 如果按照volatile-lfu就会把gender删除掉

  • 检测全部数据

  • allkeys-lru:挑选最近少使用的数据
  • allkeys-lfu:挑选最近使用次数最少的数据
  • allkeys-random:全库随机删除
  • 放弃数据驱逐

  • no-enviction : 数据不会进行任何的删除,直到内存用完,引发oom错误。
  • 总结

    下载本文
    显示全文
    专题