3、Redis 持久化
1、持久化介绍
Redis 是跑在内存里的,当程序重启或者服务崩溃,数据就会丢失,如果业务场景希望重启之后数据还在,就需要持久化,即把数据保存到可永久保存的存储设备中
Redis 提供两种方式来持久化
- RDB(Redis Database):记录 Redis 某个时刻的全部数据,这种方式本质就是数据快照,直接保存二进制数据到磁盘,后续通过加载 RDB 文件恢复数据
- AOF(Append Only File):记录执行的每条命令,重启之后通过重放命令来恢复数据,AOF 本质是记录操作日志,后续通过日志重放恢复数据
RDB 是快照恢复,AOF 是日志恢复,这是两者本质区别,我们甚至都不用去学习他们具体的实现,也能推测出他们如有下差别
- 体积方面:相同数据量下,RDB 体积更小,因为 RDB 是记录的二进制紧凑型数据
- 恢复速度:RDB 是数据快照,可以直接加载,而 AOF 文件恢复,相当于重放情况,RDB 显然会更快
- 数据完整性:AOF 记录了每条日志,RDB 是间隔一段时间记录一次,用 AOF 恢复数据通常会更为完整
用 RDB 还是 AOF
- 如果业务本身只是缓存数据且并不是一个海量访问,可以不用开持久化
如果对数据非常重视,可以同时开启 RDB 和 AOF
注意一点:同时开启的情况下,只会用 AOF 来加载,如果只有 RDB 文件而没有 AOF 文件的话,不会用 RDB 去恢复数据
如果你自主选择开启 AOF 表明要强一点的一致性,但是 AOF 文件缺失,此时不会去用 RDB,因为可能 RDB 会少很多的数据,此时启动会是一个空库 - 如果可以接受丢几分钟级别的数据,那么建议只开 RDB
Redis 官方不建议单独开 AOF:因为如果决定要走数据备份,那么镜像保存始终是数据库领域非常行之有效的解决方案,所以在配置中 RDB 是默认打开的,而 AOF 不是 - 这里也说下为什么 RDB 是几分钟才做一次持久化
虽然可以通过 fork 出的子进程来做全量快照,但是如果每一秒一次,会导致很大的性能开销
可能这一秒的快照都没完成,下一秒又 fork 出一个子进程来做快照
而 fork 子进程是会导致主线程阻塞的,所以 RDB 的快照触发间隔是比较难确定的,原则上就是不能太短,一般都是几分钟以上
2、RDB
2.1、开启 RDB
save 900 1
save 300 10
save 60 10000
这三条配置不是我们增加,是默认就存在的,这就是说 redis 默认已经开启了 RDB 持久化
这里的配置语法是 save interval num,表示每间隔 interval 秒,至少有 num 条写数据操作,写数据操作指增加、删除及更新,就会激活 RDB 持久化
2.2、RDB 文件位置
# The filename where to dump the DB
dbfilename dump.rdb
# The working directory
dir /Users/niuniumart/code/redis
RDB 文件最终会长这个样子,是二进制文件,没有可读性,但是要注意到前面有个 REDIS 字符串作为标记,这个后面讲混合持久化时也会用到
2.3、什么时候持久化
1、save -- 主动持久化:正常关闭时使用阻塞持久化
2、bgsave -- 后台持久化:定时持久化用的就是它
3、到达持久化配置阈值 -- 定时持久化
4、Redis 正常关闭时进行阻塞持久化
2.4、RDB 写入流程
- Fork 出一个子进程来专门做 RDB 持久化(Fork 会阻塞主进程、当主进程有大量写操作时消耗大量内存)
- 子进程把数据写入临时 RDB 文件
- 写完之后,用新 RDB 文件替换旧 RDB 文件
3、AOF
3.1、开启 AOF
appendonly yes
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
3.2、AOF 写入时机
执行请求时,每条日志都会写入到 AOF,会带来一定的性能损耗,Redis 的三种刷盘策略
- appendfsync always:每次请求都刷入 AOF,非常慢、非常安全
- appendfsync everysec:每秒刷一次盘,足够快了、但是在崩溃场景下你可能会丢失 1 秒的数据
- appendfsync no:不主动刷盘,让操作系统刷,一般情况 Linux 会每 30 秒刷一次盘,这种策略对性能的影响最小,但是如果发生崩溃,可能会丢失相对比较多的数据
Redis 建议是方案二,也就是每秒刷一次盘,这种方式下速度也足够快了,同时崩溃时损失的数据只有 1s,这在大多数场景都是可以接受的
我们要根据实际业务来选择,比如就是做简单的缓存,并且不存在什么超级热点缓存,那么丢失 30 秒也不是什么大事,这时候如果追求性能可以选择方案 3
方案一说实话倒是很少有场景会使用,因为 Redis 本身是无法做到完全不丢数据,Redis 的定位就不是完全可靠,通常也就没必要损耗大量性能去追求立刻刷盘
3.3、AOF 写入流程
- 将数据写入 AOF 缓存中,这个缓存名字是 aof_buf,其实就是一个 sds 数据
- aof_buf 数据刷入磁盘缓冲区(使用 write 函数来将数据写入操作系统缓冲区)
- 调用系统的 flush 函数刷盘(将操作系统缓冲区的数据刷入硬盘)
3.4、AOF 重写
AOF 是不断写入的,如此下去 AOF 就会不断膨胀,针对这个问题,Redis 采用了重写的方式来解决
- Redis 可以在 AOF 文件体积变得过大时,自动地在后台 Fork 一个子进程,专门对 AOF 进行重写
说白了就是:针对相同 Key 的操作进行合并,比如同一个 Key 的 set 操作,那就是后面覆盖前面 - 在重写过程中,Redis 不但将新的操作记录在原有的 AOF 缓冲区,而且还会记录在 AOF 重写缓冲区
一旦新 AOF 文件创建完毕,Redis 就会将重写缓冲区内容,追加到新的 AOF 文件,再用新 AOF 文件替换原来的 AOF 文件 - Fork + 两处缓存 + AOF 文件替换
Fork 子进程完成 AOF 重写,如果有新的操作,主进程将写入 "AOF 缓存" 和 "AOF 重写缓存"
写入 AOF 缓存:如果 AOF 重写过程中发生宕机,原来的 AOF 日志也是完整的,可用于恢复
写入 AOF 重写缓存:保证新的 AOF 文件不会丢失最新的写入操作,AOF 重写缓存由主进程通过管道传输给子进程
AOF 达到多大会重写,这也是配置决定,默认如下,同时满足这两个条件则重写
超过 64M 的情况下,相比上次重写时的数据大一倍,则触发重写,在周期函数来检查和触发的
# 相比上次重写时候数据增长 100%
auto-aof-rewrite-percentage 100
# 超过 64mb
auto-aof-rewrite-min-size 64mb
4、AOF 优化
AOF 的不足:体积大、加载速度慢、AOF 重写影响性能
4.1、混合持久化
混合部署实际发生在 AOF 重写阶段
- 将当前状态保存为 RDB 二进制内容,写入新的 AOF 文件
- 再将重写缓冲区的内容追加到新的 AOF 文件
- 最后替代原有的 AOF 文件
- 此时的 AOF 文件,就不再单纯的是日志数据,而是二进制数据 + 日志数据的混合体,所以叫混合持久化
打开 redis 配置文件 redis.conf:aof-use-rdb-preamble
5.0 之后默认是打开的,所以 5.0 之后只要 AOF 配置开启,默认就是混合持久化
混合特久化的 AOF 文件里开头有 REDIS 这个标记,加载时候通过这个标记来进行判断
4.2、AOF 重写优化
manifest 是文件清单,描述了当前有效的 BASEAOF、INCRAOF 是哪个,之前旧的文件标记为 HISTORYAOF,它们会被 Redis 异步删除掉
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17744717.html