文章目录
- 一、持久化机制
- 1. RDB机制
- 2. AOF机制
- RDB的优缺点
- AOF的优缺点
- 持久化机制选择
- 二、过期策略
- 常见过期策略
- Redis过期策略
- 1. 定期删除
- 2. 惰性删除
- RDB对过期键的处理
- AOF对过期键的处理
- 主从复制对过期键的处理
- 定期删除+惰性删除存在问题
- 三、淘汰策略
- Redis提供了8种淘汰策略
- 淘汰策略推荐
一、持久化机制
Redis的数据是基于内存存储的,为了防止Redis在重启或宕机等情况下数据丢失,Redis提供了两种持久化方式:RDB机制、AOF机制。
1. RDB机制
将内存中的数据以快照的方式保存到磁盘文件中(把全量数据以二进制压缩文件的方式存储到磁盘文件)。
触发快照的命令:
- bgsave:执行bgsave命令触发异步快照
- save:执行save命令触发同步块快照(同步快照会阻塞客户端的命令执行)
触发快照的时机:
- 根据Redis的配置文件redis.config中的配置,符合触发条件时自动触发异步快照bgsave
- Redis主从复制时触发
- 正常执行shutdown命令关闭服务器时,如果没有开启AOF持久化功能,那么会自动执行一次bgsave
2. AOF机制
以近乎实时的方式把执行的每条数据变动命令进行追加存储到AOF的缓存区里面, 然后再把缓存的数据写入到磁盘的AOF文件里面。
AOF默认是关闭的,通过redis.conf配置文件进行开启。
AOF日志是持续增量的备份,是基于写命令存储的可读的文本文件。AOF日志会在持续运行中持续增大,由于Redis重启过程需要优先加载AOF日志进行指令重放以恢复数据,恢复时间会无比漫长。所以需要定期进行AOF重写,对AOF日志进行瘦身。
目前AOF是Redis持久化的主流方式。
RDB的优缺点
优点:
- 适合做定时备份(冷备)
- RDB的数据恢复快
缺点:
- RDB无法做到实时持久化,若在两次bgsave间宕机,则会丢失区间(分钟级)的增量数据,不适用于实时性要求较高的场景
- RDB的cow机制中,fork子进程属于重量级操作,并且会阻塞redis主进程(执行客户端命令的线程)
AOF的优缺点
优点:
- AOF是近乎实时,一秒一次去通过一个后台的线程fsync操作,最多只会丢这一秒的数据,适合做实时备份(热备)
- AOF只是追加写日志文件,对服务器性能影响较小,速度比RDB要快,消耗的内存较少
缺点:
- AOF方式生成的日志文件太大,需要不断AOF重写,进行瘦身。
- 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基本上一致。