zoukankan      html  css  js  c++  java
  • Redis内存回收淘汰策略

    一、Redis最大内存

    1.1 预估最大内存

    Redis作为内存数据库,需要尽量把那些频繁被访问的热点数据放入Redis。

    按照二八原则,20%的数据承载了80%的访问量,可以按照这个原则来预估实际的Redis内存大小,比如后台数据库的容量是10GB,那么Redis的容量可以设置为2GB。

    二八原则是个常规的估算,有些具体情况还要具体对待:

    1. 比如针对电商的促销,可能热点数据只占全部全部商品数据的10%。
    2. 针对有个性化推荐的内容,20%的数据可能无法提供80%的访问量,可能需要40-50%的数据才行
    3. 还有一些场景,为了最大的性能,也有可能100%的数据全部放入redis,比如秒杀场景,可以把所有参与秒杀的商品数据全部放入redis。

    确定了最大内存后就可以设置redis的最大内存。

    1.2 设置最大内存

    redis默认无限使用服务器内存,为了防止在极端情况下服务器内存被耗尽,redis需要设置最大内存。

    使用命令

    src/redis-cli config set maxmemory 4gb
    

    maxmemory仅仅是指redis数据实际占用的内存(自身,数据,缓冲区),不包含碎片。

    二、内存淘汰策略

    2.1 删除过期键对象

    惰性删除

    惰性删除是在在客户端访问的时候check一下数据是否过期,如果过期则立即删除,不给客户端返回任何值。惰性删除可以降低删除对CPU的影响,但是如果一个key一直不被访问,那么这个key就有可能一直不会过期,最终会造成数据的浪费, 所以引入了定时任务删除。

    定时任务删除

    Redis内部维护的定时任务,执行流程:

    1. 随机选择20个key
    2. .如果过期的key的数量大于25%,则循环执行过期key删除
    3. 删除过程中如果发现超时(25毫秒),则进入快速回收模式:
      1. 删除的超时时间设为1毫秒
      2. 2 秒内只执行一次

    定时任务的执行频率由hz参数控制,默认为10,表述一秒执行10次。

    惰性任务和定时任务都有一定的随机性,最终还是有key一直执行不到,但是已经过期,这些key永远都不会被淘汰。所以redis还引入了相对比较精准的淘汰策略。

    2.2 内存溢出控制策略

    该值由下面参数控制。

    maxmemory-policy
    

    不淘汰策略
    noeviction是redis的默认策略,当内存使用超过配置的时候会返回错误,不会删除任何键,如果有写请求进来,redis直接报错,不提供服务,但是读请求可以照常执行。

    淘汰策略
    基于过期时间key的淘汰策略:

      1. volatile-lru:对于设置了过期时间的key,淘汰最久没有使用的key(LRU算法)
    
      2. volatile-randow:对于设置了过期时间的key,随机选择key进行淘汰
    
      3. volatile-ttl:对于设置了过期时间的key,淘汰过期时间最早的key
    
      4. volatile-lfu:对于设置了过期时间的key,淘汰但使用频率最少的键(LFU算法)
    

    所有key的淘汰策略:

    1. volatile-lru:对于所有key,淘汰久没有使用的key(LRU算法)
    2. volatile-randow:对于所有key,随机选择key进行淘汰
    3. volatile-lfu:对于所有key,淘汰使用频率最少的键(LFU算法)
    

    LRU( Least Recently Used)
    按照最少使用原则进行数据筛选,最不常用的数据会被选中,频繁使用的数据会持续保留。

    LRU会把所有数据组装成一个链表,表头代表最近使用的数据,表位表示最久没有使用的数据,用于淘汰。

    1. 新加入的数据放入表头
    2. 数据被访问后移到表头。
    3. 淘汰表尾

    LRU的核心是要维护一个链表,对于有大量key的redis来说,太重了,链表的维护会影响redis的性能。

    Redis对LRU做个改造:

    1. RedisObject会记录每个对象的lru。

    2. 当有数据会淘汰时,redis会随机选择N个数据,作为一个集合。

    3. 针对这N个数据,redis会对比起lru,把lru最小的数据淘汰。

    4. N的值redis提供了配置

      maxmemory-samples
      

      默认值为5。当配置为10时,改造的lru接近正式的lru,但是比较耗费cpu,建议保持默认即可。

    5. 当需要再次淘汰数据时,选择lru小于 < min(第一次初始化的集合的lru) 的数据进入集合,然后再基于lru进行淘汰。

    配置建议:

    1. 优先allkeys-lru:充分使用lru算法,尤其当数据冷热比较明显时,最大限度的保证热点数据补被淘汰。
    2. 没有明显的冷热,可以选择allkeys-random,随机过期即可。
    3. 如果数据有长期不过期的数据,这些数据可以不设置过期时间,建议使用voliate-lru。这样没有过期时间的数据不会被淘汰,而其他数据可以享受lru算法进行淘汰。

    三、内存淘汰流程以及影响

    如果设置了maxmemory,redis在每次执行任务时候都会尝试内存回收,当redis一直工作在内存溢出状态(used_memory > maxmemory)下,且不是noeviction策略时,会频繁的触发回收内存的操作,影响redis的性能。

    频繁回收内存成本很高:

    1. 查找可以回收的key
    2. 删除key
    3. 主从模式下,将删除命令slave。

    流程

    建议在生产环境redis的工作在maxmemory > used_memory的状态下,尽量避免频繁的内存回收开销。

    [官网参考]https://redis.io/topics/lru-cache

    作者:iBrake
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    Java对象的生命周期与作用域的讨论(转)
    [置顶] Oracle学习路线与方法
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
  • 原文地址:https://www.cnblogs.com/Brake/p/14370258.html
Copyright © 2011-2022 走看看