持久化机制有哪些
RDB(Redis DataBase)------快照
RDB就是 Redis定期 在某一时刻,把内存中的所有数据序列化成一个二进制文件,保存到磁盘。Redis主进程调用fork(),然后使用子进程的 bgsave 命令执行,这样不会阻塞主进程(写时复制技术,当主进程修改某个内存时,OS才会把这块内存复制一份给主进程修改,子进程依旧是读取旧的数据写入磁盘)。子进程负责把当前内存数据写入RDB文件,主进程继续处理客户端请求,写完后,用新RDB文件原子替换旧文件 。
优点:
- 文件紧凑:二进制文件,体积小,适合全量备份。
- 恢复速度快:重启时直接加载RDB文件,比回访AOF命令快得多。
缺点:
- 数据丢失风险大:因为是定时触发,如果中间宕机,那这保存间隔内的数据将全部丢失。
AOF(Append Only File)------追加日志
AOF 就像是记日记 。它把 Redis 执行过的所有写操作命令 (如 SET, INCR)按顺序追加到文件中(默认名为 appendonly.aof),重启时通过重放日志恢复数据。
AOF不是每条命令都直接写盘(太慢),而是先写到内核缓冲区,由策略决定何时刷盘(fsync):
- appendfsync:每次写都刷盘,数据最安全,但性能最差
- appendfsync everysec(默认):每秒刷一次盘,最多丢失一秒数据
- appendfsync no:Redis不管,让操作系统自主决定什么时候刷盘,性能最好,但不可控。
优点:
- 数据安全:默认每秒刷盘,最多只丢失一秒数据
缺点:
- 文件体积大:通常比RDB大
- 恢复速度慢:重启时要像重放电影一样执行一遍所有命令
AOF重写
日志文件会越来越大,比如对count加了100次1,那AOF会存100条INCR命令,但恢复其实只要一个SET count 100就好了,为了解决这个问题,Redis后台(bgrewriteaof)会自动内存中的数据,生成一个新的AOF文件,只保留构建当前数据所需的最小命令集,然后替换旧文件。
混合持久化
Redis 4.0引入,RDB恢复快但丢失数据,AOF安全但恢复速度慢,于是将他们结合起来。
原理:
- 在进行AOF重写时,Redis不再单纯把命令写入AOF文件
- 而是先把当前内存里的数据生成RDB快照,放在AOF文件头部
- 重写期间产生的新增命令,以AOF格式追加在文件的尾部。
当 Redis 通过 AOF 文件恢复数据时,会先加载 RDB,然后再重新执行指令恢复后半部分的增量数据,这样就可以大幅度提高数据恢复的速度了。
优点:恢复速度快,数据丢失少
Redis过期清除策略
Redis 采用的是:惰性删除 + 定期删除相结合的策略。
惰性删除------被动触发
Redis不会在Key到期那一刻立马去删他,只有当访问某个Key时,Redis才会检查这个Key是否过期,没过期正常返回,过期了就立刻删除并返回不存在。
优点:节省CPU,只有真正需要数据的时候才会去检查,不会浪费CPU资源去删除那些没人查的冷数据
缺点:浪费内存资源,如果一大堆Key已经过期了,但是永远没人去查,他们就一直在内存里,导致内存被大量无效数据占用。
定期删除------主动删除
为了解决惰性删除的内存泄露问题,Redis会隔一段时间就随机抽取一些设置了过期时间的Key,检查是否删除。这里有一个核心判断:Redis抽取的Key中,如果超过25%过期,Redis会认为过期键比例高,会再次抽取,直到过期比例下降。
优点:释放内存,能够清理掉那些没人查的冷数据,保证内存不会被垃圾填满
缺点 :销毁CPU,如果过期键太多,Redis会频繁删除,占用主线程CPU,导致处理业务速度变慢。
Redis的内存淘汰机制
Redis 的内存淘汰机制是指当 Redis 使用的内存超过 maxmemory 限制时,通过配置的淘汰策略,选择一部分 key 删除,以防止进程继续占用内存甚至被 OOM kill。
在面试中,不要死记硬背那 8 种策略,要学会**"拆解组合"**。所有的策略其实就是 2 个维度 的排列组合:
- "从哪里挑?" (范围) :是 所有 Key (allkeys) 还是 设置了过期时间的 Key (volatile)?
- "按什么规则踢?" (算法) :是 LRU 、LFU 、随机 、TTL 还是 不踢?
Redis 4.0 之后,一共有 8 种策略。我们可以把它分为 4 大类:
不淘汰(默认策略)
noeviction:
- 机制:内存满了直接报错OOM command not allowed,拒绝写入新数据,但允许读
- 场景:你需要保证数据完整性,不能随便丢,通常用于把Redis当数据库用
LRU------最近最少使用
- allkeys-lru(最常用)
- 机制:从所有key中,淘汰那个最近最少使用的
- 场景:缓存场景首选
- volatile-lru
- 机制: 只从 设置了 TTL 的 Key 中,淘汰最近最少使用的
- 场景: 当你有些数据是持久化的(没设 TTL),有些是缓存的(设了 TTL),只想淘汰缓存数据时。
LFU------最不常用(Redis4.0)
- allkeys-lfu
- 机制:从所有Key中,淘汰访问频率最低的
- 场景:针对热点数据更有效
- volatile-lfu
- 机制:只从设置了TTL的Key中淘汰访问频率最低的
Random随机&TTL快过期的
- allkeys-random:从所有Key里随机删除一个
- volatile-random:从设置TTL的key里随机删除一个
- volatile-ttl"从设置TTL的key里,挑选TTL最短的Key淘汰