这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战」
过期删除策略
过期数据的清理可以有三种删除策略:
- 定时删除:对设置了过期时间的键,设计一个到期执行的执行器,在key过期的时候立即将键值删除。
- 惰性删除:获取键时才进行判断,如果过期再删除,不过期就返回该键。
- 定期删除:设置一个定时执行的定时器,每隔一段时间,检查并删除过期的值。
定时删除
- 内存友好,但对CPU不友好,而且可能导致缓存雪崩的情形。
惰性删除
- CPU友好,但内存不友好。
定期删除
上述两种的折衷考虑。
redis实际使用的是惰性删除和定期删除的策略。
redis - 惰性删除
所有读写数据库的redis命令,都会先通过特定函数(db.c/expireIfNeeded)的检查:
- 如果过期,删除
- 不过期则进入读写操作指令。
redis - 定期删除
redis服务器会周期性地执行某个函数(redis.c/activeExpireCycle),随机从数据库中抽取部分记录,做过期判断与过期删除。
复制模式
复制模式下,从服务器是不会主动删除过期键的。只有当:
-
主服务器删除了一个过期键后,会向所有从服务器发送del命令,来告知从服务器删除该过期键。
-
从服务器仅当受到主服务器的命令,才删除过期键。
- 否则,读命令再从服务器上对过期键的查询,和未过期键的拆线呢相同。
持久化
-
两种方式:快照、AOF
- 快照:一次全量备份
- AOF:连续增量备份
快照 - RDB
快照备份的是内存的二进制序列化形式,存储紧凑。
- 是一个经过压缩的二进制文件
使用SAVE,或者BGSAVE,或者根据服务器选项定期执行,来创建一个新的RDB文件。
- 不会保存过期的键。
由于RDB的全量性质,因此AOF的更新频率通常高于RDB,数据也较新,因此:
- 如果开启了AOF持久化,那么服务器会优先使用AOF来进行启动时数据载入。
- 仅当关闭了AOF且开启了RDB,服务器才会使用RDB来还原。
RDB载入
启动服务器时,如果开启了RDB功能,那么服务器会载入RDB文件
- 服务器为主服务器模式:检查RDB中的键,如果过期了就不载入。
- 服务器为从服务器模式:载入RDB中所有的键。
不过,因为主从服务器在进行数据同步的时候,从服务器的数据库就会被清空,所以一般来讲,过期键对载入RDB文件的从服务器也不会造成影响。
RDB文件载入时,直到载入完成,服务器都会一直处于阻塞状态。
RDB写入状态
手动写入
RDB通过两个命令进行手动写入。
-
当执行save时:
redis服务器会阻塞,拒绝所有客户端发送的命令。
-
当执行BGSave时:
BGSave时通过子进程执行的,因此该场景下Redis服务器仍可以继续处理客户端命令请求,但对于如下三个命令会执行不同的处理:
-
SAVE:当执行BGSAVE时,SAVE命令会被拒绝。
服务器禁止SAVE命令和BGSAVE命令同时执行是为了避免父进程(服务器进程)和子进程同时执行两个rdbSave调用,防止产生竞争条件。
-
BGSAVE:和上面相同的道理,BGSAVE也会被拒绝。
-
BGRewriteAOF:和BGSave不会同时执行。
- BGSAVE先执行,那么BGRewriteAof命令会被推迟到BgSave命令执行完毕后执行。
- BgRewrite先执行,那么BGSAVE会被拒绝。
此处考虑的不是冲突,而是性能考虑(两个子线程并发且都执行了大量的磁盘写入操作)
-
自动写入
BGSave不阻塞服务器主进程,因此Redis可以通过服务器设置,让服务器间隔时间一段时间自动执行一次BGSAVE指令。
指令为:
save 900 1 save 300 10 save 60 10000save的指令是互相兼容的关系,上面三个指令(这个是save选项的默认条件)指的是:
只要满足以下三个条件中的任意一个,BGSAVE命令就会被执行:
❑服务器在900秒之内,对数据库进行了至少1次修改。
❑服务器在300秒之内,对数据库进行了至少10次修改。
❑服务器在60秒之内,对数据库进行了至少10000次修改。
定期执行的逻辑是:
- 必须先满足时间上的间隔到了
- 随后再考虑数据的修改次数
AOF日志
aof日志是内存数据修改的指令记录文本,存储没有那么紧凑,长时间运行会很大,因此需要定期重写以及瘦身。
AOF载入
如果键过期但没来得及删除,那么AOF文件不会有对应记录。
如果被删除了,那么AOF文件末尾会追加一条del命令,来记录该键已被删除。
AOF重写
AOF重写时,不会写入过期的键。