天天看点

Redis系列(十七)、Redis中的内存淘汰策略和过期删除策略介绍内存淘汰策略LRU算法LFU算法 过期删除策略AOF和RDB的过期删除策略

我们知道Redis是分布式内存数据库,基于内存运行,可是有没有想过比较好的服务器内存也不过几百G,能存多少数据呢,当内存占用满了之后该怎么办呢?Redis的内存是否可以设置限制? 过期的key是怎么从内存中删除的?不要怕,本篇我们一起来看一下Redis的内存淘汰策略是如何释放内存的,以及过期的key是如何从内存中删除的。

目录

介绍

内存淘汰策略

LRU算法

LFU算法

​过期删除策略

AOF和RDB的过期删除策略

Redis6系列文章:

Redis系列(一)、CentOS7下安装Redis6.0.3稳定版

Redis系列(二)、数据类型之字符串String 

Redis系列(三)、数据类型之哈希Hash

Redis系列(四)、数据类型之列表List

Redis系列(五)、数据类型之无序集合Set

Redis系列(六)、数据类型之有序集合ZSet(sorted_set)

Redis系列(七)、常用key命令

Redis系列(八)、常用服务器命令 

Redis系列(九)、Redis的“事务”及Lua脚本操作

Redis系列(十)、详解Redis持久化方式AOF、RDB以及混合持久化

Redis系列(十一)、Redis6新特性之ACL安全策略(用户权限管理)

Redis系列(十二)、Redis6集群搭建及原理(主从、哨兵、集群)

Redis系列(十三)、pub/sub发布与订阅(对比List和Kafka)

Redis系列(十四)、Redis6新特性之RESP3与客户端缓存(Client side caching)

Redis系列(十五)、Redis6新特性之集群代理(Cluster Proxy)

Redis系列(十六)、Redis6新特性之IO多线程

介绍

开篇提到Redis是基于内存的数据库,当内存满了的时候会发生什么呢?Redis的内存是否可以设置限制? 过期的key是怎么从内存中删除的?

其实在Redis中是可以设置内存最大限制的,因此我们不用担心Redis占满机器的内存影响其他服务,这个参数maxmemory是可以配置的:

#配置文件
maxmemory <bytes>
下面的写法均合法:
maxmemory 1024000
maxmemory 1GB
maxmemory 1G
maxmemory 1024KB
maxmemory 1024K
maxmemory 1024MB
...

#命令行
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "0"
127.0.0.1:6379> config set maxmemory 1GB
OK
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "1073741824"
           
Redis系列(十七)、Redis中的内存淘汰策略和过期删除策略介绍内存淘汰策略LRU算法LFU算法 过期删除策略AOF和RDB的过期删除策略
maxmemory参数默认值为0。因32位系统支持的最大内存为4GB,所以在32位系统上Redis的默认最大内存限制为3GB;在64位系统上默认Redis最大内存即为物理机的可用内存;

内存淘汰策略

Redis中共有下面八种内存淘汰策略:

  • volatile-lru:设置了过期时间的key使用LRU算法淘汰;
  • allkeys-lru:所有key使用LRU算法淘汰;
  • volatile-lfu:设置了过期时间的key使用LFU算法淘汰;
  • allkeys-lfu:所有key使用LFU算法淘汰;
  • volatile-random:设置了过期时间的key使用随机淘汰;
  • allkeys-random:所有key使用随机淘汰;
  • volatile-ttl:设置了过期时间的key根据过期时间淘汰,越早过期越早淘汰;
  • noeviction:默认策略,当内存达到设置的最大值时,所有申请内存的操作都会报错(如set,lpush等),只读操作如get命令可以正常执行;
LRU、LFU和volatile-ttl都是近似随机算法;

使用下面的参数maxmemory-policy配置淘汰策略:

#配置文件
maxmemory-policy noeviction

#命令行
127.0.0.1:6379> config get maxmemory-policy
1) "maxmemory-policy"
2) "noeviction"
127.0.0.1:6379> config set maxmemory-policy allkeys-random
OK
127.0.0.1:6379> config get maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-random"
           
Redis系列(十七)、Redis中的内存淘汰策略和过期删除策略介绍内存淘汰策略LRU算法LFU算法 过期删除策略AOF和RDB的过期删除策略
在缓存的内存淘汰策略中有FIFO、LRU、LFU三种,其中LRU和LFU是Redis在使用的。

FIFO是最简单的淘汰策略,遵循着先进先出的原则,这里简单提一下:

Redis系列(十七)、Redis中的内存淘汰策略和过期删除策略介绍内存淘汰策略LRU算法LFU算法 过期删除策略AOF和RDB的过期删除策略

LRU算法

LRU(Least Recently Used)表示最近最少使用,该算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

LRU算法的常见实现方式为链表:

新数据放在链表头部 ,链表中的数据被访问就移动到链头,链表满的时候从链表尾部移出数据。

Redis系列(十七)、Redis中的内存淘汰策略和过期删除策略介绍内存淘汰策略LRU算法LFU算法 过期删除策略AOF和RDB的过期删除策略

而在Redis中使用的是近似LRU算法,为什么说是近似呢?Redis中是随机采样5个(可以修改参数maxmemory-samples配置)key,然后从中选择访问时间最早的key进行淘汰,因此当采样key的数量与Redis库中key的数量越接近,淘汰的规则就越接近LRU算法。但官方推荐5个就足够了,最多不超过10个,越大就越消耗CPU的资源。

但在LRU算法下,如果一个热点数据最近很少访问,而非热点数据近期访问了,就会误把热点数据淘汰而留下了非热点数据,因此在Redis4.x中新增了LFU算法。

在LRU算法下,Redis会为每个key新增一个3字节的内存空间用于存储key的访问时间;

LFU算法

LFU(Least Frequently Used)表示最不经常使用,它是根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。

LFU算法反映了一个key的热度情况,不会因LRU算法的偶尔一次被访问被误认为是热点数据。

LFU算法的常见实现方式为链表:

新数据放在链表尾部 ,链表中的数据按照被访问次数降序排列,访问次数相同的按最近访问时间降序排列,链表满的时候从链表尾部移出数据。

Redis系列(十七)、Redis中的内存淘汰策略和过期删除策略介绍内存淘汰策略LRU算法LFU算法 过期删除策略AOF和RDB的过期删除策略
过期删除策略

前面介绍的LRU和LFU算法都是在Redis内存占用满的情况下的淘汰策略,那么当内存没占满时在Redis中过期的key是如何从内存中删除以达到优化内存占用的呢? 

官网:https://redis.io/commands/expire#expire-accuracy 

在Redis中过期的key不会立刻从内存中删除,而是会同时以下面两种策略进行删除:

  • 惰性删除:当key被访问时检查该key的过期时间,若已过期则删除;已过期未被访问的数据仍保持在内存中,消耗内存资源;
  • 定期删除:每隔一段时间,随机检查设置了过期的key并删除已过期的key;维护定时器消耗CPU资源;

Redis每10秒进行一次过期扫描:

  1. 随机取20个设置了过期策略的key;
  2. 检查20个key中过期时间中已过期的key并删除;
  3. 如果有超过25%的key已过期则重复第一步;

这种循环随机操作会持续到过期key可能仅占全部key的25%以下时,并且为了保证不会出现循环过多的情况,默认扫描时间不会超过25ms;

AOF和RDB的过期删除策略

前面介绍了Redis的持久化策略RDB和AOF,当Redis中的key已过期未删除时,如果进行RDB和AOF的持久化操作时候会怎么操作呢?

  • 在RDB持久化模式中我们可以使用save和bgsave命令进行数据持久化操作
  • 在AOF持久化模式中使用rewriteaof和bgrewriteaof命令进行持久化操作

这四个命令都不会将过期key持久化到RDB文件或AOF文件中,可以保证重启服务时不会将过期key载入Redis。

为了保证一致性,在AOF持久化模式中,当key过期时候,会同时发送DEL命令给AOF文件和所有节点;

从节点不会主动的删除过期key除非它升级为主节点或收到主节点发来的DEL命令;

希望本文对你有帮助,请点个赞鼓励一下作者吧~ 谢谢!

继续阅读