• 【Redis】内存回收:内存淘汰策略


    【Redis】内存回收:内存淘汰策略

    一、Redis内存回收-过期key处理

    如果你发现,平时在操作 Redis 时,并没有延迟很大的情况发生,但在某个时间点突然出现一波延时,其现象表现为:变慢的时间点很有规律,例如某个整点,或者每间隔多久就会发生一波延迟。如果是出现这种情况,那么你需要排查一下,业务代码中是否存在设置大量 key 集中过期的情况。

    在学习Redis缓存的时候我们说过,可以通过expire命令给Redis的key设置TTL(存活时间):

    1653983366243

    可以发现,当key的TTL到期以后,再次访问name返回的是nil,说明这个key已经不存在了,对应的内存也得到释放。从而起到内存回收的目的。

    Redis本身是一个典型的key-value内存存储数据库,因此所有的key、value都保存在之前学习过的Dict结构中。不过在其database结构体中,有两个Dict:一个用来记录key-value;另一个用来记录key-TTL。

    1653983423128

    1653983606531

    Redis之所以性能强,最主要的原因就是基于内存存储。然而单节点的Redis其内存大小不宜过大,会影响持久化或主从同步性能。
    当内存使用达到上限时,就无法存储更多数据了。为了解决这个问题,Redis提供了一些策略实现内存回收:

    Redis主要有2种过期数据回收策略:

    惰性删除

    • 惰性删除指的是当我们查询key的时候才对key进行检测,如果已经达到过期时间,则删除。显然,他有⼀个缺点就是如果这些过期的key没有被访问,那么他就⼀直无法被删除,而且⼀直占用内存。

    周期删除

    • 顾名思义是通过一个定时任务,周期性的抽样部分过期的key,然后执行删除。执行周期有两种:
      • Redis服务初始化函数initServer()中设置定时任务,按照server.hz的频率来执行过期key清理,模式为SLOW
      • Redis的每个事件循环前会调用beforeSleep()函数,执行过期key清理,模式为FAST
    • SLOW模式规则:
      • 执行频率受server.hz影响,默认为10,即每秒执行10次,每个执行周期100ms。
      • 执行清理耗时不超过一次执行周期的25%.默认slow模式耗时不超过25ms
      • 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期
      • 如果没达到时间上限(25ms)并且过期key比例大于10%,再进行一次抽样,否则结束
    • FAST模式规则(过期key比例小于10%不执行 ):
      • 执行频率受beforeSleep()调用频率影响,但两次FAST模式间隔不低于2ms
      • 执行清理耗时不超过1ms
      • 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期
        如果没达到时间上限(1ms)并且过期key比例大于10%,再进行一次抽样,否则结束

    二、Redis内存回收-内存淘汰策略

    内存淘汰:就是当Redis内存使用达到设置的上限时,主动挑选部分key删除以释放更多内存的流程。

    这个删除旧数据的逻辑也是需要消耗时间的,而具体耗时的长短,要取决于你配置的淘汰策略:

    • allkeys-lru:不管 key 是否设置了过期,淘汰最近最少访问的 key

    • volatile-lru:只淘汰最近最少访问、并设置了过期时间的 key

    • allkeys-random:不管 key 是否设置了过期,随机淘汰 key

    • volatile-random:只随机淘汰设置了过期时间的 key

    • allkeys-ttl:不管 key 是否设置了过期,淘汰即将过期的 key

    • noeviction:不淘汰任何 key,实例内存达到 maxmeory 后,再写入新数据直接返回错误

    • allkeys-lfu:不管 key 是否设置了过期,淘汰访问频率最低的 key(4.0+版本支持)

    • volatile-lfu:只淘汰访问频率最低、并设置了过期时间 key(4.0+版本支持)

    比较容易混淆的有两个:

    • LRU(Least Recently Used),最少最近使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
    • LFU(Least Frequently Used),最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高。

    Redis的数据都会被封装为RedisObject结构:

    image-20221119022226898

    最后用一副图来描述当前的这个流程吧

    image-20221119023146948

  • 相关阅读:
    #define定义标识符详解
    傅里叶变换和其图像处理中的应用
    面试中常用消息中间件对比
    效率翻倍:使用 ERP 系统自动执行这 5 项任务
    免杀对抗-C#+go语言-混淆+防反编译+分离
    TMP451
    MATLAB小技巧(19)矩阵分析--主成分分析
    java 版本企业招标投标管理系统源码+多个行业+tbms+及时准确+全程电子化
    python常见面试题二
    antd table给某些表头设置样式
  • 原文地址:https://blog.csdn.net/weixin_63566550/article/details/127960388