> 文章列表 > redis持久化RDBAOF混合持久化

redis持久化RDBAOF混合持久化

redis持久化RDBAOF混合持久化

1 Redis持久化RDB

Redis 的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制 来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的持久化机制。 Redis 的持久化机制有两种,第一种是RDB快照,第二种是 AOF 日志。快照是一次全量备份AOF 日志是连续的增量备份快照是内存数据的二进制序列化形式,在存储上非常紧凑,而 AOF 日志记录的是内存数据修改的指令记录文本。AOF 日志在长期的运行过程中会变的无比庞大,数据库重启时需要加载 AOF 日志进行指令重放,这个时间就会无比漫长。 所以需要定期进行 AOF 重写,给 AOF 日志进行瘦身。
redis持久化RDBAOF混合持久化

1.1 RDB快照

在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里。

我们知道 Redis 是单线程程序,这个线程要同时负责多个客户端套接字的并发读写操作内存数据结构的逻辑读写。在服务线上请求的同时,Redis 还需要进行内存快照,内存快照要求 Redis 必须进行文件 IO 操作,可文件 IO 操作是不能使用多路复用 API

这意味着单线程同时在服务线上的请求还要进行文件 IO 操作,文件 IO 操作会严重拖 垮服务器请求的性能。还有个重要的问题是为了不阻塞线上的业务,就需要边持久化边响应 客户端请求。持久化的同时,内存数据结构还在改变,比如一个大型的 hash 字典正在持久 化,结果一个请求过来把它给删掉了,还没持久化完呢,怎么办?

Redis 使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化

fork(多进程)

Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。

redis持久化RDBAOF混合持久化

  • 子进程刚刚产生时,它和父进程共享内存里面的代 码段和数据段。这时你可以将父子进程想像成一个连体婴儿,共享身体。这是 Linux 操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的一瞬间,内存的 增长几乎没有明显变化。
  • 子进程做数据持久化,它不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是进程不一样,它必须持续服务客户端请求,然后对内存 数据结构进行不间断的修改
  • 这个时候就会使用操作系统的 COW 机制来进行数据段页面的分离。数据段是由很多操 作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。
  • 子进程因为数据没有变化,它能看到的内存里的数据在进程产生的一瞬间就凝固了,再也不会改变,这也是为什么 Redis 的持久化叫快照的原因。接下来子进程就可以非常安心的遍历数据了进行序列化写磁盘了。

1.2 何时触发RDB快照

RDB触发的规则分为两大类,分别是手动触发和自动触发:

自动触发:

  1. 配置触发规则
  2. shutdown触发
  3. flushall触发

手动触发:

  1. save
  2. bgsave

1.2.1 自动触发

1、配置触发规则

在Redis安装目录下的redis.conf配置文件中搜索snapshot即可快速定位,配置文件默认注释了下面三行数据,通过配置规则来触发RDB的持久化,需要开启或者根据自己的需求按照规则来配置。

redis持久化RDBAOF混合持久化

save 3600 1 -> 3600秒内有1个key被修改,触发RDB
save 300 100 -> 300 秒内有100个key被修改,触发RDB
save 60 10000 -> 60 秒内有10000个key被修改,触发RDB
rdbcompression yes   #配置压缩
dbfilename dump.rdb  #配置RDB文件的名称
rdbchecksum yes      #文件完整性校验
...

2、shutdown触发

shutdown触发Redis的RDB持久化机制非常简单,我们在客户端执行shutdown即可。

3 flushall触发

flushall也会生成rdb文件,但是这里一定要特别注意,flushall是删库跑路,它是清空dump.rdb文件

1.2.2 手动触发

手动触发RDB持久化的方式可以使用save命令和bgsave命令,这两个命令的区别如下。
save:执行save指令,阻塞Redis的其他操作,会导致Redis无法响应客户端请求,不建议使用。
bgsave:执行bgsave指令,Redis后台异步进行快照的保存操作,此时Redis仍然能响应客户端的请求。

1.2.3 持久化文件的备份

在实际的生产环境中,我们一般不会使用主节点Master来进行持久化备份,我们会通过在Redis的多个从服务器上进行RDB持久化备份,这样是为了对Redis数据的多次备份,防止出现网络分区或者部分节点宕机甚至是硬件损坏的情况发生。

1.3 RDB快照总结

优势

  • RDB是一种表示某个即时点的Redis数据的紧凑文件。RDB文件适合用于备份。例如,你可能想要每小时归档最近24小时的RDB文件,每天保存近30天的RDB快照。这允许你很容易的恢复不同版本的数据集以容灾。
  • RDB非常适合于灾难恢复,作为一个紧凑的单一文件,可以被传输到远程的数据中心,或者是Amazon S3(可能得加密)。
  • RDB最大化了Redis的性能,因为Redis父进程持久化时唯一需要做的是启动(fork)一个子进程,由子进程完成所有剩余工作。父进程实例不需要执行像磁盘IO这样的操作。
  • RDB在重启保存了大数据集的实例时比AOF要快。

劣势

  • Fork 的时候,内存中的数据被克隆了一份,膨胀性需要考虑。

  • 虽然 Redis 在 fork 时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。

  • 在备份周期在一定间隔时间做一次备份,所以如果 Redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改。

2 Redis持久化AOF

2.1 AOF简介

Redis配置文件中开启,AOF持久化方案进行备份时,客户端所有请求的写命令都会被追加到AOF缓冲区中,缓冲区中的数据会根据Redis配置文件中配置的同步策略来同步到磁盘上的AOF文件中,同时当AOF的文件达到重写策略配置的阈值时,Redis会对AOF日志文件进行重写,给AOF日志文件瘦身。Redis服务重启的时候,通过加载AOF日志文件来恢复数据。

redis持久化RDBAOF混合持久化

2.2 AOF配置

AOF默认不开启,默认为appendonly no,开启则需要修改为appendonly yesAOF配置文件的名称默认为appendonly.aof

redis持久化RDBAOF混合持久化

同步频率配置

AOF日志是以文件的形式存在的,当程序对AOF日志文件进行写操作时,实际上将内容写到了内核为文件描述符分配的一个内存缓冲区中,随后内核会异步的将缓冲区中的数据刷新到磁盘中。如果缓冲区中的数据没来得及刷回磁盘时,服务器宕机了,这些数据就会丢失
因此Redis通过调用Linux操作系统的glibc提供的fsync(int fid)来将指定文件的内容强制从内核缓冲区刷回磁盘,以此来保证缓冲区中的数据不会丢失。不过这是一个IO操作,相比Redis的性能来说它是非常慢的,所以不能频繁的执行。

Redis配置文件中有三种刷新缓冲区的配置:

redis持久化RDBAOF混合持久化

appendfsync always
每次Redis写操作,都写入AOF日志,这种配置理论上Linux操作系统扛不住,因为Redis的并发远远超过了Linux操作系统提供的最大刷新频率,就算Redis写操作比较少的情况,这种配置也是非常耗性能的,因为涉及到IO操作,所以这个配置基本上不会用

appendfsync everysec
每秒刷新一次缓冲区中的数据到AOF文件,这个Redis配置文件中默认的策略,兼容了性能和数据完整性的折中方案,这种配置,理论上丢失的数据在一秒钟左右

appendfsync no
Redis进程不会主动的去刷新缓冲区中的数据到AOF文件中,而是直接交给操作系统去判断,这种操作也是不推荐的,丢失数据的可能性非常大。

2.3 AOF修复功能

AOF持久化机制正常恢复与RDB持久化机制的恢复是一样的,都只需要将备份文件放置到Redis的工作目录下,Redis启动时就会自动的加载。AOF持久化机制提供了AOF文件异常时恢复的功能,这个功能在AOF文件损坏的场景中经常被使用到。

开启aof配置,进行损坏修复测试

redis-check-aof

lizheng@lz-x:/usr/local/redis-rdb$ sudo redis-check-aof appendonly.aof
AOF analyzed: size=122, ok_up_to=122, ok_up_to_line=27, diff=0
AOF is valid

验证通过,接下来手动改一行 你好啊

...
set
$7
address
你好啊
china

验证:AOF is not valid.

lizheng@lz-x:/usr/local/redis-rdb$ sudo redis-check-aof appendonly.aof
0x              6f: Expected prefix '$', got: '�'
AOF analyzed: size=129, ok_up_to=85, ok_up_to_line=25, diff=44
AOF is not valid. Use the --fix option to try fixing it.

修复:redis-check-aof --fix appendonly.aof

lizheng@lz-x:/usr/local/redis-rdb$ sudo redis-check-aof --fix appendonly.aof
0x              6f: Expected prefix '$', got: '�'
AOF analyzed: size=129, ok_up_to=85, ok_up_to_line=25, diff=44
This will shrink the AOF from 129 bytes, with 44 bytes, to 85 bytes
Continue? [y/N]: y
Successfully truncated AOF
lizheng@lz-x:/usr/local/redis-rdb$ sudo redis-check-aof appendonly.aof
AOF analyzed: size=85, ok_up_to=85, ok_up_to_line=20, diff=0
AOF is valid

2.4 AOF重写

AOF属于日志追加的形式来存储Redis的写指令,这会导致大量冗余的指令存储,从而使得AOF日志文件非常庞大,比如同一个key被写了10000次,最后却被删除了,这种情况不仅占内存,也会导致恢复的时候非常缓慢,因此Redis提供重写机制来解决这个问题。Redis的AOF持久化机制执行重写后,保存的只是恢复数据的最小指令集,我们如果想手动触发可以使用如下指令:

bgrewriteaof

Redis4.0后的重写使用的是RDB快照AOF指令拼接的方式,在AOF文件的头部是RDB快照的二进制形式的数据,尾部是快照产生后发生的写入操作的指令。
由于重写AOF文件时,会对Redis的性能带来一定的影响,因此也不能随便的进行自动重写,Redis提供两个配置用于自动进行AOF重写的指标,只有这两个指标同时满足的时候才会发生重写:

redis持久化RDBAOF混合持久化

Redis 会记录上次重写时的 AOF 大小,默认配置是当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于 64M 时触发。重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定 Redis 要满足一定条件才会进行重写。

  • auto-aof-rewrite-percentage:设置重写的基准值,文件达到 100% 时开始重写(文件是原来重写后文件的 2 倍时触发)。

  • auto-aof-rewrite-min-size:设置重写的基准值,最小文件 64MB。达到这个值开始重写。

系统载入时或者上次重写完毕时,Redis 会记录此时 AOF 大小,设为 base_size,如果 Redis 的 AOF 当前大小 >= base_size +base_size*100% (默认) 且当前大小 >=64mb (默认) 的情况下,Redis 会对 AOF 进行重写。

例如:文件达到 70MB 开始重写,降到 50MB,下次什么时候开始重写?100MB

重写流程

  1. bgrewriteaof触发重写,判断是否存在bgsave或者bgrewriteaof正在执行,存在则等待其执行结束再执行
  2. 主进程fork子进程,防止主进程阻塞无法提供服务,类似RDB
  3. 子进程遍历Redis内存快照中数据写入临时AOF文件,同时会将新的写指令写入aof_buf和aof_rewrite_buf两个重写缓冲区,前者是为了写回旧的AOF文件,后者是为了后续刷新到临时AOF文件中,防止快照内存遍历时新的写入操作丢失。
  4. 子进程结束临时AOF文件写入后,通知主进程
  5. 主进程会将上面3中的aof_rewirte_buf缓冲区中的数据写入到子进程生成的临时AOF文件中
  6. 主进程使用临时AOF文件替换旧AOF文件,完成整个重写过程

redis持久化RDBAOF混合持久化

3 混合持久化

Redis4.0后大部分的使用场景都不会单独使用RDB或者AOF来做持久化机制,而是兼顾二者的优势混合使用。其原因是RDB虽然快,但是会丢失比较多的数据,不能保证数据完整性;AOF虽然能尽可能保证数据完整性,但是性能确实是一个诟病,比如重放恢复数据。其日志文件结构如下:

redis持久化RDBAOF混合持久化

混合持久化通过aof-use-rdb-preamble yes开启,Redis 4.0以上版本默认开启
redis持久化RDBAOF混合持久化

4 总结

最后来总结这两者,到底用哪个更好呢?

  • 推荐是两者均开启
  • 如果对数据不敏感,可以选单独用RDB
  • 不建议单独用AOF,因为可能会出现Bug
  • 如果只是做纯内存缓存,可以都不用