https://blog.csdn.net/qq_31387317/article/details/95315166
1、概念
Redis中有两种持久化形式——RDB(Redis Database)、AOF(Append Only File)
- RDB:在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot),也就是说它存的是数据。
- AOF:AOF 文件是一个只进行追加操作的日志文件(append only log),日志中记录每一次执行的指令。
2、RDB
- fork子进程进行write操作(由于fork子进程会将父进程的所有资源到copy到子进程中,所以如果文件过大,可能会阻塞主进程)
- 如果Redis data非常大,持久化RDB是非常耗时、耗性能的。
2.1 fork开销
首先明确 fork子进程并不会造成太大的开销,因为Linux等os提供了一种COW(copy on write—写时复制技术)。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段,只有当父进程在修改数据时,父进程会copy该数据区域形成一个新的副本,然后父进程会在这个新的区域进行操作。
3、AOF
- 追加记录到缓存
- 启用后台线程,将缓存刷新到磁盘
3.1 AOF追加阻塞
当开启AOF持久化时,默认以及常用的同步硬盘策略是everysec(每s一刷),对于这种方式,Redis使用另一个线程每s执行fsync同步磁盘。试想一个问题,假设硬盘资源繁忙,fsync刷盘缓慢,主线程该如何做?
主线程写入AOF缓冲区后会对比上次AOF同步时间
- 如果距上次同步成功时间在2S内,主线程直接返回
- 如果距上次同步成功时间超过2s,主线程阻塞,直到同步操作完成
发现两个问题:
- everysec配置最多可能丢失2s数据,不是1s
- 如果系统fsync慢会阻塞主线程
3.2 AOF重写
当AOF体积过大时就会进行AOF重写,将一些无效的日志命令删除掉。AOF重写由于会消耗一定时间,所以Redis将会fork另外的进程进行处理。但是这就出现了一个问题,在重写AOF的过程中,主进程还在执行命令,且往现有的AOF文件中写数据,如果此时系统崩溃了,那重写的AOF文件就和旧的AOF文件不一致了。所以在重写AOF时,主进程还会降新增log写到重写缓冲区中,当子进程完成重写后,主进程收到通知则将重写缓冲区里的数据写到这个新的AOF文件中(注意,如果数据很多,有可能会造成主进程阻塞,所以redis后面通过管道机制,主进程只需要把数据放到管道里,不需要子进程立马响应,然后子进程把所有的数据处理完了在返回给主进程就好)
4、优缺点
RDB优点:
- 体积更小:相同的数据量rdb数据比aof的小,因为rdb是紧凑型文件
- 恢复更快:因为rdb是数据的快照,基本上就是数据的复制,不用重新读取再写入内存
- 性能更高:父进程在保存rdb时候只需要fork一个子进程,无需父进程的进行其他io操作,也保证了服务器的性能。
RDB缺点:
- 不安全。对数据敏感的场景不合适,因为RDB是需要fork以个子进程将当前Redis中的全部数据通过IO写入磁盘,必然这将会消耗一定的时间。 因此你可能会至少 5 分钟才保存一次 RDB 文件,如果期间Redis崩溃,将会导致丢失这几分钟的数据。
AOF优点(自然相对于RDB的缺点):
- 更安全。适合数据敏感的场景,由于AOF会追加每一条执行命令到日志中,因此不容易丢失数据。
AOF缺点:
- 由于体积大,自然数据恢复的时间更长,性能更差