文章目录

  • 一、持久化机制
  • 1. RDB机制
  • 2. AOF机制
  • RDB的优缺点
  • AOF的优缺点
  • 持久化机制选择
  • 二、过期策略
  • 常见过期策略
  • Redis过期策略
  • 1. 定期删除
  • 2. 惰性删除
  • RDB对过期键的处理
  • AOF对过期键的处理
  • 主从复制对过期键的处理
  • 定期删除+惰性删除存在问题
  • 三、淘汰策略
  • Redis提供了8种淘汰策略
  • 淘汰策略推荐



一、持久化机制

Redis的数据是基于内存存储的,为了防止Redis在重启或宕机等情况下数据丢失,Redis提供了两种持久化方式:RDB机制、AOF机制。

1. RDB机制

将内存中的数据以快照的方式保存到磁盘文件中(把全量数据以二进制压缩文件的方式存储到磁盘文件)。

触发快照的命令:

  1. bgsave:执行bgsave命令触发异步快照
  2. save:执行save命令触发同步块快照(同步快照会阻塞客户端的命令执行)


触发快照的时机:

  1. 根据Redis的配置文件redis.config中的配置,符合触发条件时自动触发异步快照bgsave
  2. Redis主从复制时触发
  3. 正常执行shutdown命令关闭服务器时,如果没有开启AOF持久化功能,那么会自动执行一次bgsave

2. AOF机制

以近乎实时的方式把执行的每条数据变动命令进行追加存储到AOF的缓存区里面, 然后再把缓存的数据写入到磁盘的AOF文件里面。

AOF默认是关闭的,通过redis.conf配置文件进行开启。

AOF日志是持续增量的备份,是基于写命令存储的可读的文本文件。AOF日志会在持续运行中持续增大,由于Redis重启过程需要优先加载AOF日志进行指令重放以恢复数据,恢复时间会无比漫长。所以需要定期进行AOF重写,对AOF日志进行瘦身。

目前AOF是Redis持久化的主流方式。

RDB的优缺点

优点:

  1. 适合做定时备份(冷备)
  2. RDB的数据恢复快

缺点:

  1. RDB无法做到实时持久化,若在两次bgsave间宕机,则会丢失区间(分钟级)的增量数据,不适用于实时性要求较高的场景
  2. RDB的cow机制中,fork子进程属于重量级操作,并且会阻塞redis主进程(执行客户端命令的线程)

AOF的优缺点

优点:

  1. AOF是近乎实时,一秒一次去通过一个后台的线程fsync操作,最多只会丢这一秒的数据,适合做实时备份(热备)
  2. AOF只是追加写日志文件,对服务器性能影响较小,速度比RDB要快,消耗的内存较少

缺点:

  1. AOF方式生成的日志文件太大,需要不断AOF重写,进行瘦身。
  2. AOF重演命令式的恢复数据,速度显然比RDB要慢

持久化机制选择

建议AOF、RDB一起用。单独用RDB可能会丢失很多数据,单独用AOF数据恢复没RDB来的快,出问题的时候第一时间用RDB恢复,然后AOF做数据补全,冷备热备一起用。

二、过期策略

对于设置了过期时间的数据,当数据过期之后,Redis就需要将这些数据进行清除,释放占用的内存空间。

常见过期策略

  • 定时删除
    在设置某个 key 的过期时间同时,我们创建一个定时器,让定时器在该过期时间到来时,立即执行对其进行删除的操作。
  • 优点:定时删除对内存是最友好的,key一旦过期就能立即从内存中删除;
  • 缺点:对CPU最不友好,删除过期键会占用一部分CPU时间,对服务器的响应时间和吞吐量造成影响。
  • 定期删除
    每隔一段时间,我们就对一些key进行检查,删除里面过期的key。
  • 优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键占用的内存。
  • 缺点:难以确定删除操作执行的时长和频率。
    如果执行的太频繁,定期删除策略变得和定时删除策略一样,对CPU不友好
    如果执行的太少,那又和惰性删除一样了,过期键占用的内存不会及时得到释放。在获取某个键时,如果某个键的过期时间已经到了,但是还没执行定期删除,那么就会返回这个键的值,这是一定务不能忍受的。
  • 惰性删除
    设置该 key 过期时间后,我们不去管它,当需要该 key 时,我们在检查其是否过期,如果过期,我们就删掉它。
  • 优点:对 CPU 友好,我们只会在使用该键时才会进行过期检查,对于很多用不到的 key 不用浪费时间进行过期检查;
  • 缺点:对内存不友好,如果一个键已经过期,但是一直没有使用,那么该键就会一直存在内存中,如果数据库中有很多这种使用不到的过期键,这些键便永远不会被删除,内存永远不会释放,从而造成内存泄漏

Redis过期策略

Redis中主要使用定期删除+惰性删除两种数据过期清除策略。

1. 定期删除

Redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除。注意这里是随机抽取的。

过期键的定期删除策略由activeExpireCycle函数实现,每当Redis服务器的周期性操作serverCron函数执行时,activeExpireCycle函数就会被调用,它在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。

为什么要随机抽取?

假如Redis存了大量的key ,每隔100ms就遍历所有的设置过期时间的key的,会给CPU带来很大的负载。

为什么不用定时删除策略?

定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。

2. 惰性删除

定期删除可能导致很多过期的key到了时间并没有被删除掉,这时就要使用到惰性删除。

在获取某个key的时候,redis会检查这个key如果是否设置了过期时间并且过期了,如果是的话就删除。

RDB对过期键的处理

生成RDB文件时:

在执行save命令或者bgsave命令创建一个新的RDB文件时,程序会对数据库中的键进行检查,已过期的键不会被保存到新创建的RDB文件中。

加载RDB文件时:
在启动Redis服务器时,如果服务器只开启了RDB持久化,那么服务器将会载入RDB文件:

  • 如果服务器以主服务器模式运行,在载入RDB文件时,程序会对文件中保存的键进行检查,未过期的键会被载入到数据库中,过期键会被忽略。
  • 如果服务器以从服务器模式运行,在载入RDB文件时,文件中保存的所有键,不论是否过期,都会被载入到数据库中。
    因为主从服务器在进行数据同步(完整重同步)的时候,从服务器的数据库会被清空,所以一般情况下,过期键对载入RDB文件的从服务器不会造成影响。

AOF对过期键的处理

AOF文件写入

如果数据库中的某个键已经过期,并且服务器开启了AOF持久化功能,当过期键被定期删除或者惰性删除后,程序会向AOF文件追加一条DEL命令,显式记录该键已被删除。

以惰性删除为例:

  • 获取名称为test的key
  • 检查发现该key设置了过期时间并已经过期
  • 从内存中删除该key
  • 追加一条删除该key的命令到AOF文件
  • 返回空

AOF文件重写

在执行AOF文件重写时,程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中。

主从复制对过期键的处理

  • 主服务器在删除一个过期键后,会显式地向所有从服务器发送一个DEL命令,告知从服务器删除这个过期键。
  • 从服务器在执行客户端发送的读命令时,即使发现该键已过期也不会删除该键,照常返回该键的值。
  • 从服务器只有接收到主服务器发送的DEL命令后,才会删除过期键。

定期删除+惰性删除存在问题

如果某个key过期后,定期删除没删除成功,然后也没再次去请求key,也就是说惰性删除也没生效。

这时,如果大量过期的key堆积在内存中,redis的内存会越来越高,导致redis的内存块耗尽。那么就应该采用内存淘汰机制。

三、淘汰策略

当Redis内存不足时,会通过内存淘汰策略删除部分键值对。

Redis内存设置

配置文件redis.conf中,通过参数 maxmemory<bytes> 来设定最大内存。

Redis提供了8种淘汰策略

  • 不淘汰
  • noeviction:不进行淘汰数据。一旦缓存被写满,再有写请求进来,Redis就不再提供服务,而是直接返回错误。
  • 从全部数据中进行淘汰
  • allkeys-lru:在所有的键值对中,移除最近最少使用的键值对。
  • allkeys-lfu:在所有的键值对中,移除最近最不频繁使用的键值对。
  • allkeys-random:在所有键值对中,随机移除某个key。
  • 从设置了过期时间的数据中进行淘汰
  • volatile-ttl:在设置了过期时间的键值对中,移除即将过期的键值对。
  • volatile-lru:在设置了过期时间的键值对中,移除最近最少使用的键值对。
  • volatile-lfu:在设置了过期时间的键值对中,移除最近最不频繁使用的键值对。
  • volatile-random:在设置了过期时间的键值对中,随机移除某个键值对。

淘汰策略推荐

  • 通常情况下推荐优先使用 allkeys-lru 策略。这样可以充分利用 LRU 这一经典缓存算法的优势,把最近最常访问的数据留在缓存中,提升应用的访问性能。
  • 如果你的业务数据中有明显的冷热数据区分,建议使用 allkeys-lru 策略。
  • 如果业务应用中的数据访问频率相差不大,没有明显的冷热数据区分,建议使用 allkeys-random 策略,随机选择淘汰的数据就行。
  • 如果没有设置过期时间的键值对,那么 volatile-lru,volatile-lfu,volatile-random 和 volatile-ttl 策略的行为, 和 noeviction基本上一致。