Redis——持久化原理探究

720 阅读4分钟

简介

redis的操作在内存中,读写速度极快,QPS高达10w,常用来作为缓存服务器以减缓数据库的压力。我们知道内存中的数据极易丢失,比如在机器宕机时会丢失,所以需要一种持久化的机制来保护redis的数据不会因为故障而丢失。
这种机制就是Redis的持久化机制:

  • 快照
  • AOF日志

快照

快照原理

前面redis基础篇中提到,redis是单线程的,这个线程需要同时处理客户端的请求和内存数据结构的逻辑读写,显然难以在保持高性能的前提下完成这些工作。
所以redis使用操作系统的多进程COW(copy on write)写时复制机制来完成快照持久化。 copy on write原理看这篇Linux写入复制的文章

fork(多线程)

Redis在持久化的时候会调用glibc的函数fork()产生一个子进程,快照持久化工作全部交给子进程处理,父进程则继续处理客户端请求。子进程在产生时完全共享父进程共享内存里面的代码段和数据段。
子进程做数据持久化时不会修改现有的内存数据结构,它只是遍历内存中的数据然后序列化写入磁盘中。与此同时,父进程还在接受客户端的数据交互请求,然后对内存中的数据进行不断的修改。
当客户端请求对某个数据进行修改时,就会使用操作系统的COW机制来进行数据段页面的分离。简单来说就是数据段由多个数据页组成,找到这个数据所在的数据页,系统会将这个数据页复制一份,在这个复制页上进行数据修改。
子进程的数据没有变化,因此它看到的内存里的数据在晋城产生的一瞬间就凝固了,就像拍照的快照一样。

AOF 日志

AOF原理

AOF日志存储的是redis的顺序指令序列,按照执行顺序存储,AOF只记录对内存进行修改的指令记录,有点像MySQL的Binlog。
AOF写入流程:
redis写入流程

Redis 在收到客户端的修改指令时会先进行参数校验,如果没有问题就立即将指令存储到AOF日志,也就是写入到磁盘中。指令存储到AOF日志后,即使宕机,内存中的数据丢失了,也可以通过 回放AOF日志对数据进行重现,使得redis恢复到宕机前的状态。


在redis长期运行的过程中,会接收到很多的指令,这将导致AOF日志越来越大。而AOF日志中很多命令是重复覆盖的,我们只需保留最新的数据即可,比如某个 key = aaa 的数据初始值value = 1,在redis运行的过程中该数据进行过1000次修改,并且最新value = 111 。
此时AOF中有1000个关于key=aaa的指令记录,而实际上我们只需要记录其最新的 value=111 即可保证数据持久化。
所以我们需要对AOF进行瘦身

AOF 重写

顾名思义就是对AOF的命令进行重写,达到瘦身的目的。
redis中提供bgrewriteaof命令来对AOF日志进行重写,重写原理:

  • 创建一个子进程对内存进行遍历转换成一系列redis操作指令,序列化一个新的AOF日志文件中,序列化完毕后再将操作期间发生的增量AOF日志追加到新的AOF日志中,追加完毕马上用新的AOF日志替换旧AOF日志

持久化小结

  • 快照是通过fork一个子进程的方式进行的,很耗费资源的操作,并且会遍历整个内存,大块写磁盘将加重系统负载
  • AOF的fsync是一个耗时的IO操作,会降低redis的性能,同时增加了系统的IO负担。

所以redis一般是从节点进行数据持久化,而主节点与客户端交互

混合持久化方案

rdb + 增量AOF日志的形式:当重启一个redis时,先使用rdb恢复再用增量的AOF日志进行指令重放,达到快速启动恢复数据的效果。

redis混合持久化