从零开始学Redis(3) — 持久化:如何选择RDB和AOF

  • Post author:
  • Post category:其他


因为redis是基于内存保存数据,如果宕机,就会丢失数据。

因此redis提供了两种持久化机制

  1. RDB,基于快照
  2. AOF,基于日志


什么是RDB

RDB — redis会将数据集的快照dump到dump.rdb文件,做一个全量备份用于恢复。


Redis如何一边响应请求,一边持久化?

我们知道redis是基于单线程多路复用,因此我们不能同时进行内存快照以及响应请求。

而redis因此在持久化时会fork一个子进程,持久化完全由子进程处理,父进程继续处理客户端请求。

子进程只会对数据结构遍历读取然后序列化到磁盘中,但是父进程会持续修改内存数据结构。

因此redis使用了操作系统的COW(copy on write)机制进行数据段page的共享读写。

它把所有数据按每4k一个page来分割,然后子进程就对每一个page去读取然后序列号写到磁盘,而父进程就响应请求,当出现数据改变时,就将对应的page复制一份分离出来然后修改。当然随着修改增多,page会越来越多,内存也会增长,但是worst case只是原有数据内存的两倍;同时redis作为一个缓存,冷数据比例比较高,因此基本上是小部分页面被复制分离。如下图。


RDB的优点:

dump.rdb是个二进制文件,使用RDB恢复非常快


RDB的缺点:

1.dump的时候比较耗费资源

2.只使用RDB恢复的话,基本上会丢失大量数据,因为我们不可能每时每刻都dump备份下来。


什么是AOF

AOF就是redis存储顺序指令序列的log,只记录了内存修改的指令记录。

因此我们可以通过执行aof文件来进行指令重放,以此来恢复数据。

PS:和mysql等数据库不同,redis是先执行了指令,然后再写log(可能是因为和mysql等不同,redis只有执行了这个命令才知道这个命令是否有效)。


突然宕机,AOF日志还没写到磁盘怎么办?

实际上程序对AOF日志写操作时,就是将内容写到kernel为fd分配的一个内存缓存,然后kernel会自动异步将数据刷回磁盘。所以突然宕机,可能日志还没刷到磁盘。怎么办?

linux有个fsync函数,可以强制把fd对应的内容从内核缓存刷到磁盘。但是fsync是个磁盘IO操作,所以会很慢。

所以redis一般会每隔1s执行一次fsync去刷到磁盘。


AOF的优点:

基本上不会数据丢失或很少


AOF的缺点:

1.恢复时是执行日志重放,所以如果日志比较长,就会比较慢。。。

2.fsync是个耗时的IO操作,会增加系统IO负担


混合持久化

没错,大人选择全都要。。

我们选择redis提供的混合持久化模式,rdb快照和增量aof日志同时保存。这里的aof日志就不是全量日志,而是从持久化开始到持久化结束的增量AOF日志,因此这部分AOF日志会很小。

当我们重启redis时,先加载rdb内容,然后再重放增量AOF文件,以此提高效率。



版权声明:本文为oJeremy12原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。