持久化
RDB(Redis DataBase)
RDB 是一次全量备份, RDB 是内存数据的二进制序列化形式,在存储上非常紧凑
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快文件直接卖到内存里
如何进行(底层执行)
多进程 COW(Copy On Write) 机制
Reds会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何I0操角的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
Fork
- Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
- 在Liux程序中,fork会产生一个和父程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linx中引入了“写时复制技术”
- 一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
RDB持久化流程
- 执行 bgsave 命令,Redis 父进程判断当前是否存在正在执行的子进 程,如 RDB/AOF 子进程,如果存在 bgsave 命令直接返回。
- 父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞,通 过 info stats 命令查看 latest_fork_usec 选项,可以获取最近一个 fork 操作的耗 时,单位为微秒。
- 父进程 fork 完成后,bgsave 命令返回 “Background saving started” 信息 并不再阻塞父进程,可以继续响应其他命令。
- 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后 对原有文件进行原子替换。执行 lastsave 命令可以获取最后一次生成 RDB 的 时间,对应 info 统计的 rdb_last_save_time 选项。
- 进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence 下的 rdb_* 相关选项。
dump.rdb文件
redis.conf
AOF
概述
AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的 指令记录。
假设 AOF 日志记录了自 Redis 实例创建以来所有的修改性指令序列,那么就可以通过 对一个空的 Redis 实例顺序执行所有的指令,也就是「重放」,来恢复 Redis 当前实例的内 存数据结构的状态。
Redis 会在收到客户端修改指令后,先进行参数校验,如果没问题,就立即将该指令文本存储到 AOF 日志中,也就是先存到磁盘,然后再执行指令。这样即使遇到突发宕机,已经存储到 AOF 日志的指令进行重放一下就可以恢复到宕机前的状态。通过 appendfsync 参数可以控制实时/秒级持久化 。
执行流程
- 所有的写入命令会追加到 aof_buf(缓冲区)中。
- AOF 缓冲区根据对应的策略向硬盘做同步操作。
- 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
- 当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。
AOF日志瘦身
概述
Redis 在长期运行的过程中,AOF 的日志会越变越长。如果实例宕机重启,重放整个 AOF 日志会非常耗时,导致长时间 Redis 无法对外提供服务。所以需要对 AOF 日志瘦身。
Redis 提供了 bgrewriteaof 指令用于对 AOF 日志进行瘦身。其原理就是开辟一个子进程对内存进行遍历转换成一系列 Redis 的操作指令,序列化到一个新的 AOF 日志文件中。序列化完毕后再将操作期间发生的增量 AOF 日志追加到这个新的 AOF 日志文件中,追加完毕后就立即替代旧的 AOF 日志文件了,瘦身工作就完成了。
执行流程
AOF 重写可以通过 auto-aof-rewrite-min-siz e 和 auto-aof-rewrite- percentage 参数控制自动触发,也可以使用 bgrewriteaof 命令手动触发。
子进程执行期间使用 copy-on-write 机制与父进程共享内存,避免内 存消耗翻倍。AOF 重写期间还需要维护重写缓冲区,保存新的写入命令避免 数据丢失。
注意:单机下部署多个实例时,为了防止出现多个子进程执行重写操作, 建议做隔离控制,避免 CPU 和 IO 资源竞争。
混合持久化
概述
重启 Redis 时,我们很少使用 RDB 来恢复内存状态,因为会丢失大量数据。我们通常 使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实 例很大的情况下,启动需要花费很长的时间。
将 RDB 文 件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自 持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。
于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可 以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。