本文主要介绍Redis内存回收淘汰策略


目录

  • 一、Redis最大内存
    • 1.1 预估最大内存
    • 1.2 设置最大内存
  • 二、内存淘汰策略
    • 2.1 删除过期键对象
    • 2.2 内存溢出控制策略
  • 三、内存淘汰流程以及影响


一、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内部维护的定时任务,执行流程:

Redis内存回收淘汰策略_Redis

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

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

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

2.2 内存溢出控制策略

Redis内存回收淘汰策略_Redis_02

该值由下面参数控制。

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会把所有数据组装成一个链表,表头代表最近使用的数据,表位表示最久没有使用的数据,用于淘汰。

Redis内存回收淘汰策略_Redis_03

  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内存回收淘汰策略_Redis_04

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