参考博文1《Redis内存满了的几种解决方法》https://blog.csdn.net/u014590757/article/details/79788076
参考博文2《关于Redis数据过期策略》https://www.cnblogs.com/chenpingzhao/p/5022467.html
参考博文3《为什么Redis内存不宜过大》https://blog.csdn.net/houyongqian88/article/details/53866641

Redis三种过期键删除策略

  • ==被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key==
  • 主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key
  • maxmemory:当前已用内存超过maxmemory限定时,触发主动清理策略maxmemory-policy

1.被动删除

被动删除介绍

  • 被动删除的条件:1.key设置了过期时间;2.key过期了;3.key有被访问到
  • 这种删除策略对CPU是友好的,删除操作只有在不得不的情况下才会进行,不会其他的expire key上浪费无谓的CPU时间。
  • 但是这种策略对内存不友好,一个key已经过期,但是在它被操作之前不会被删除,仍然占据内存空间。==如果有大量的过期键存在但是又很少被访问到,那会造成大量的内存空间浪费。==

被动删除的缺点

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

2.主动删除 hz

2.1 serverCron

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

serverCron 实现, 它主要执行以下操作

  • 更新服务器的各类统计信息,比如时间、内存占用、数据库占用情况等。
  • 清理数据库中的过期键值对。
  • 对不合理的数据库进行大小调整。
  • 关闭和清理连接失效的客户端。
  • 尝试进行 AOF 或 RDB 持久化操作。
  • 如果服务器是主节点的话,对附属节点进行定期同步。
  • 如果处于集群模式的话,对集群进行定期同步和连接测试。

Redis 将 serverCron 作为时间事件来运行, 从而确保它每隔一段时间就会自动运行一次, 又因为 serverCron 需要在 Redis 服务器运行期间一直定期运行, 所以它是一个循环时间事件: serverCron 会一直定期执行,直到服务器关闭为止。

在 Redis 2.6 版本中, 程序规定 serverCron 每秒运行 10 次, 平均每 100 毫秒运行一次。 从 Redis 2.8 开始, 用户可以通过修改 hz选项来调整 serverCron 的每秒执行次数。

1
2
3
127.0.0.1:6530> config get hz
1) "hz"
2) "10" # 次数/秒 默认10

2.2 定期删除

Redis会周期性的随机测试一批设置了过期时间的key并进行处理。测试到的已过期的key将被删除。典型的方式为,Redis每秒做10次如下的步骤:

  • 随机测试100个设置了过期时间的key
  • 删除所有发现的已过期的key
  • 若删除的key超过25个则重复步骤1

==当REDIS运行在主从模式时,只有主结点才会执行上述这两种过期删除策略,然后把删除操作”del key”同步到从结点。==

3.maxmemory

3.1 动态增加内存

1
2
3
4
5
6
7
# 查看当前最大内存
10.19.19.82:6530> config get maxmemory
1) "maxmemory"
2) "26843545600" # 25G:25*1024*1024*1024

# 设置成30G
config set maxmemory 32212254720 # 30G:30*1024*1024*1024

3.2 Redis内存淘汰策略 maxmemory-policy

  • 当前已用内存超过maxmemory限定时,触发内存淘汰策略。默认值noeviction
  • 当mem_used内存已经超过maxmemory的设定,对于所有的读写请求,都会触发redis.c/freeMemoryIfNeeded(void)函数以清理超出的内存。注意这个清理过程是阻塞的,直到清理出足够的内存空间。==所以如果在达到maxmemory并且调用方还在不断写入的情况下,可能会反复触发主动清理策略,导致请求会有一定的延迟。==
  • 清理时会根据用户配置的maxmemory-policy来做适当的清理(一般是LRU或TTL),这里的LRU或TTL策略并不是针对redis的所有key,而是以配置文件中的maxmemory-samples个key作为样本池进行抽样清理。
  • maxmemory-samples在redis-3.0.0中的默认配置为5,如果增加,会提高LRU或TTL的精准度,redis作者测试的结果是当这个配置为10时已经非常接近全量LRU的精准度了,并且增加maxmemory-samples会导致在主动清理时消耗更多的CPU时间,建议:
    • 尽量不要触发maxmemory,最好在mem_used内存占用达到maxmemory的一定比例后,需要考虑调大hz以加快淘汰,或者进行集群扩容。
    • 如果能够控制住内存,则可以不用修改maxmemory-samples配置;如果Redis本身就作为LRU cache服务(这种服务一般长时间处于maxmemory状态,由Redis自动做LRU淘汰),可以适当调大maxmemory-samples。

关于LRU算法

  • LRU算法,least RecentlyUsed,最近最少使用算法。也就是说默认删除最近最少使用的键。
  • 但是一定要注意一点!redis中并不会准确的删除所有键中最近最少使用的键,而是随机抽取3个键,删除这三个键中最近最少使用的键。
  • 那么3这个数字也是可以设置的,对应位置是配置文件中的maxmemory-samples.
序号 规则名称 规则说明
1 ==volatile-lru== 使用LRU算法删除一个键(只对设置了生存时间的键)
2 allkeys-lru 使用LRU算法删除一个键
3 volatile-random 随机删除一个键(只对设置了生存时间的键)
4 allkeys-random 随机删除一个键
5 volatile-ttl 删除生存时间最近的一个键
6 noeviction 不删除键,只返回错误(默认)
1
2
3
4
5
6
7
8
127.0.0.1:6530> config get maxmemory-policy
1) "maxmemory-policy"
2) "volatile-lru"


127.0.0.1:6530> config get maxmemory-samples
1) "maxmemory-samples"
2) "3"