两种持久化机制
Redis 的持久化机制有两种,第一种是快照,第二种是 AOF日志
快照(RDB)
方式:一次全量备份
存储内容:内存数据的二进制序列化形式,在存储上非常紧凑。
原理:使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化。
触发机制:
- 手动触发(save:直接阻塞服务器,知道RDB结束。实例较大的话会造成长时间阻塞。和bgsave:执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段。)
- 自动触发:
2.1“save m n”。表示m秒内数据集存在n次修改时,自动触发bgsave。
2.2 从节点执行全量复制操作,主节点自动执行bgsave生成RDB文 319
件并发送给从节点.
2.3 debug reload命令重新加载Redis
2.4 默认情况下执行shutdown命令时,如果没有开启AOF持久化功能则 自动执行bgsave。
过程: - 调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。(子进程刚刚产生时,它和父进程共享内存里面的代 码段和数据段)。
- 子进程做数据持久化,它不会修改现有的内存数据结构,它只是对数据结构进行遍历读 取,然后序列化写到磁盘中。父进程,持续服务客户端请求,然后对内存数据结构进行不间断的修改。(操作系统的 COW 机制来进行数据段页面的分离:数据段是由很多操作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的, 还是进程产生时那一瞬间的数据。它能看到的内存里的数据在进程产生的一瞬间就凝固了。)
- 子进程发送信号给父进程表示完成,父进程更新统计信息。
优点:
紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照。非常适用于备份,全量复制等场景。Redis加载RDB恢复数据远远快于AOF的方式。
缺点:
没办法做到实时持久化/秒级持久化。(执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。)
兼容性问题:RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式 的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题。
AOF日志
方式:连续的增量备份
存储内容:记录了自 Redis 实例创建以来所有的修改性指令序列。(长期的运行过程中,AOF日志会变的无比庞大,数据库重启时需要加载 AOF日志进行指令重放,这个时间就会无比漫长。 所以需要定期进行 AOF 重写,给 AOF日志进行瘦身。)
过程:Redis 会在收到客户端修改指令后,先进行参数校验,如果没问题,就立即将该指令文本存储到 AOF 日志中,也就是先存到磁盘,然后再执行指令。这样即使遇到突发宕机,已经存储到 AOF 日志的指令进行重放一下就可以恢复到宕机前的状态。
AOF瘦身:
就是开辟一个子进程对内存进行遍历转换成一系列 Redis 的操作指令,序列化到一个新的 AOF 日志文件中。 序列化完毕后再将操作期间发生的增量 AOF 日志追加到这个新的 AOF 日志文件中,追加完毕后就立即替代旧的 AOF日志文件了,瘦身工作就完成了。
写文件原理和宕机处理:
程序对 AOF 日志文件进行写操作时,实际上是将内容写到了内核为文件描述符分配的一个内存缓存中,然后内核会异步将脏数据刷回到磁盘的。
AOF 日志内容可能还没有来得及完全刷到磁盘中,这个时候就会出现日志丢失。那该怎么办?Linux 的 glibc 提供了 fsync(int fd)函数可以将指定文件的内容强制从内核缓存刷到磁盘。但是 fsync 是一个 磁盘 IO 操作,它很慢!如果 Redis 执行一条指令就要 fsync 一次,那么 Redis 高性能的 地位就不保了。所以在生产环境的服务器中,Redis 通常是每隔 1s 左右执行一次 fsync 操作,周期 1s 是可以配置的。
混合持久化
将 rdb 文 件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可 以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。