• Redis(二十):Redis数据过期和淘汰策略详解(转)


    原文地址:https://yq.aliyun.com/articles/257459#

    背景

    Redis作为一个高性能的内存NoSQL数据库,其容量受到最大内存限制的限制。

    用户在使用Redis时,除了对性能,稳定性有很高的要求外,对内存占用也比较敏感。在使用过程中,有些用户会觉得自己的线上实例内存占用比自己预想的要大。

    事实上,实例中的内存除了保存原始的键值对所需的开销外,还有一些运行时产生的额外内存,包括:

    1. 垃圾数据和过期Key所占空间
    2. 字典渐进式Rehash导致未及时删除的空间
    3. Redis管理数据,包括底层数据结构开销,客户端信息,读写缓冲区等
    4. 主从复制,bgsave时的额外开销
    5. 其它

    本文主要分析第一项Redis过期策略对内存的影响

    设置过期时间

    • expire key time(以秒为单位)--这是最常用的方式
    • setex(String key, int seconds, String value)–字符串独有的方式

    注意:

    • 除了字符串自己独有设置过期时间的方法外,其他方法都需要依靠expire方法来设置时间
    • 如果没有设置时间,那缓存就是永不过期
    • 如果设置了过期时间,之后又想让缓存永不过期,使用persist key

    Redis三种Key过期策略

        1、被动删除(惰性删除)

      当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key。

      只有key被操作时(如GET),REDIS才会被动检查该key是否过期,如果过期则删除之并且返回NIL。

        a.这种删除策略对CPU是友好的,删除操作只有在不得不的情况下才会进行,不会其他的expire key上浪费无谓的CPU时间。

        b.但是这种策略对内存不友好,一个key已经过期,但是在它被操作之前不会被删除,仍然占据内存空间。如果有大量的过期键存在但是又很少被访问到,那会造成大量的内存空间浪费。expireIfNeeded(redisDb *db, robj *key)函数位于src/db.c。

      但仅是这样是不够的,因为可能存在一些key永远不会被再次访问到,这些设置了过期时间的key也是需要在过期后被删除的,我们甚至可以将这种情况看作是一种内存泄露----无用的垃圾数据占用了大量的内存,而服务器却不会自己去释放它们,这对于运行状态非常依赖于内存的Redis服务器来说,肯定不是一个好消息

      优点:删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)

      缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)

        2、主动删除

      由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key。

      先说一下时间事件,对于持续运行的服务器来说, 服务器需要定期对自身的资源和状态进行必要的检查和整理, 从而让服务器维持在一个健康稳定的状态, 这类操作被统称为常规操作(cron job)。在 Redis 中, 常规操作由 redis.c/serverCron 实现。

      优点:通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用–处理"定时删除"的缺点,定期删除过期key–处理"惰性删除"的缺点。

      缺点:在内存友好方面,不如"定时删除",在CPU时间友好方面,不如"惰性删除"。

      难点:合理设置删除操作的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间做一次删除)(这个要根据服务器运行情况来定了)

        3、maxmemory

    当前已用内存超过maxmemory限定时,触发主动清理策略。

    • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用 的数据淘汰
    • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数 据淘汰
    • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据 淘汰
    • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
    • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
    • no-enviction(驱逐):(默认)禁止驱逐数据

    相关最佳实践优化配置

      • 不要放垃圾数据,及时清理无用数据
        实验性的数据和下线的业务数据及时删除;
      • key尽量都设置过期时间
        对具有时效性的key设置过期时间,通过redis自身的过期key清理策略来降低过期key对于内存的占用,同时也能够减少业务的麻烦,不需要定期手动清理了.
      • 单Key不要过大
        给用户排查问题时遇到过单个string的value有43M的,也有一个list 100多万个大成员占了1G多内存的。这种key在get的时候网络传输延迟会比较大,需要分配的输出缓冲区也比较大,在定期清理的时候也容易造成比较高的延迟. 最好能通过业务拆分,数据压缩等方式避免这种过大的key的产生。
      • 不同业务如果公用一个业务的话,最好使用不同的逻辑db分开
        从上面的分析可以看出,Redis的过期Key清理策略和强制淘汰策略都会遍历各个db。将key分布在不同的db有助于过期Key的及时清理。另外不同业务使用不同db也有助于问题排查和无用数据的及时下线.
  • 相关阅读:
    阅读<SQL语言艺术>实践五
    <SQL语言艺术>阅读计划
    文本类文件与VS关联实践
    接口开发原则
    逻辑部分开发原则
    <海量数据库解决方案>2011022301
    5800对于存储卡密码设置问题
    [转]Delphi用户登录窗口框架
    20世纪科学界最重要的12本书
    [转]UDP/TCP穿越NAT的P2P通信方法研究(UDP/TCP打洞 Hole Punching)
  • 原文地址:https://www.cnblogs.com/shamo89/p/8358755.html
Copyright © 2020-2023  润新知