Redis原理二:持久化

Redis 的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的持久化机制。

初始RDB和AOF

Redis 的持久化机制有两种,第一种是快照(RDB),第二种是 AOF 日志。快照是一次全量备份,是二进制序列化形式,在存储上非常紧凑,非常适合做冷备,恢复速度特别快。AOF 日志是连续的增量备份,记录的是指令记录文本,长期运行势必会变的非常庞大(b毕竟是文本而不是二进制),因此要定期的rewrite,去掉旧的指令。AOF非常适合来保证数据不丢失(尽可能的不丢失)。

《Redis原理二:持久化》

RDB

我们知道 Redis 是单线程程序,这个线程不仅要负责多个客户端套接字的并发读写操作,还要负责内存数据结构的逻辑读写。

如果这种单线程除了负责上述操作之外,还要进行文件IO操作,这些文件IO操作会严重拖垮服务器请求的性能。

那怎么办呢?
redis使用操作系统的多进程COW机制来实现快照持久化。

COW

Redis 在持久化时会调用 glibc 的函数fork产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这是 Linux 操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的一瞬间,内存的增长几乎没有明显变化。
子进程做数据持久化,它不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不间断的修改。

RDB工作流程

  1. redis根据配置自己尝试去生成rdb快照文件
  2. fork一个子进程出来
  3. 子进程尝试将数据dump到临时的rdb快照文件中
  4. 完成rdb快照文件的生成之后,就替换之前的旧的快照文件
    dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照

AOF

AOF日志记录对内存进行修改的指令记录,它可以通过对一个空的 Redis 实例顺序执行所有的指令,也就是「重放」,来恢复 Redis 当前实例的内存数据结构的状态。

Redis 会在收到客户端修改指令后,进行参数校验进行逻辑处理后,如果没问题,先写入os cache的,然后每隔一定时间再fsync一下到日志中。

配置AOF的fsync策略,有三种策略可以选择 :

  1. always: 每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低; 确保说redis里的数据一条都不丢,那就只能这样了

  2. everysec: 每秒将os cache中的数据fsync到磁盘,这个最常用的,生产环境一般都这么配置,性能很高,QPS还是可以上万的

  3. no: 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了

AOF rewrite

内存毕竟是有限的,有些数据会被LRU算法清除掉,有些数据会被定期删除+惰性删除机制删除掉,总之redis会不断淘汰数据。

所以很多内存中已经不存在的数据,在AOF日志中还可能存在着对应的指令,这样会不断的膨胀。

所以AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了; redis内存只剩下10万; 基于内存中当前的10万数据构建一套最新的日志,到AOF中; 覆盖之前的老日志; 确保AOF日志文件不会过大,保持跟redis内存数据量一致

rewrite流程

  1. redis fork一个子进程
  2. 子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志
  3. redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件
  4. 子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中
  5. 用新的日志文件替换掉旧的日志文件

Redis4.0混合持久化

重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。

Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。

于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。

点赞