开发者

Redis的持久化之RDB和AOF机制详解

开发者 https://www.devze.com 2025-06-28 09:57 出处:网络 作者: ?abc!
目录概述RDB(Redis Database)核心原理触发方式手动触发自动触发AOF(Append-Only File)核心原理配置方式AOF实现步骤AOF重写基本概念触发方式重写过程重写过程中主线程有哪些地方会被阻塞?为什么不复用原AOF日志R
目录
  • 概述
  • RDB(Redis Database)
    • 核心原理
    • 触发方式
      • 手动触发
      • 自动触发
  • AOF(Append-Only File)
    • 核心原理
      • 配置方式
        • AOF实现步骤
          • AOF重写
            • 基本概念
            • 触发方式
            • 重写过程
            • 重写过程中主线程有哪些地方会被阻塞?
            • 为什么不复用原AOF日志
        • RDB vs AOF
          • 如何保证数据一致性
            • 总结

              概述

              Redis 提供 RDB 和 AOF 两种持久化机制,它们在数据安全性、性能、恢复速度等方面有显著差异。

              为什么要进行持久化?如果是大数据量的恢复,会有下述的影响

              • 会对数据库带来巨大的压力,
              • 数据库的性能不如Redis。导致程序响应慢
              • 实现数据的持久化,避免从后端数据库中恢复数据

              RDB(Redis Database)

              核心原理

              RDB持久化是把当前进程数据生成快照保存到磁盘上的过程,由于是某一时刻的快照,那么快照中的值要早于或者等于内存中的值

              RDB文件默认为当前工作目录下的dump.rdb,可以根据配置文件中的dbfilename和dir设置RDB的文件名和文件位置

              Redis的持久化之RDB和AOF机制详解

              触发方式

              有下述两种触发方式

              • 手动触发:分别对应save和bgsave命令
              • 自动触发:以下4种情况时会自动触发

              手动触发

              • 手动触发:分别对应save和bgsave命令
              • save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存 比较大的实例会造成长时间阻塞,线上环境不建议使用
              • bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子 进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短

              fork()是由操作系统提供的函数,作用是创建当前进程的一个副本作为子进程

              fork一个子进程,子进程会把数据集先写入临时文件,写入成功之后,再替换之前的RDB文件,用二进制压缩存储,这样可以保证RDB文件始终存储的是完整的持久化内容

              自动触发

              自动触发:以下4种情况时会自动触发

              redis.conf中配置save m n,即在m秒内有n次修改时,自动触发bgsave生成rdb文件;

              save <seconds> <changes>

              表示在seconds秒内,至少有changes次变化,就会自动触发gbsave命令

              • 主从复制时,从节点要从主节点进行全量复制时也会触发bgsave操作,生成当时的快照发送到从节点
              • 执行debug reload命令重新加载redis时也会触发bgsave操作;
              • 默认情况下执行shutdown命令时,如果没有开启aof持久android化,那么也会触发bgsave操作;

              AOF(Append-Only File)

              针对RDB不适合实时持久化的问题,Redis提供了AOF持久化方式来解决.

              核心原理

              AOF日志采用写后日志,即先写内存,后写日志

              • AOF持久化会把被执行的写命令写到AOF文件的末尾,记录数据的变化。
              • 默认情况下,Redis是没有开启AOF持久化的
              • 开启后,每执行一条更改Redis数据的命令,都会把该命令追加到AOF文件中,这是会降低Redis的性能,但大部分情况下这个影响是能够接受的
              • 另外使用较快的硬盘可以提高AOF的性能

              Redis的持久化之RDB和AOF机制详解

              配置方式

              通过配置redis.conf文件开启AOF持久化

              # appendonly参数开启AOF持久化
              appendonly no
              
              # AOF持久化的文件名,默认是appendonly.aof
              appendfilename "appendonly.aof"
              
              # AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
              dir ./
              
              # 同步策略
              # appendfsync alwjsays
              appendfsync everysec
              # appendfsync no
              
              # aof重写期间是否同步
              no-appendfsync-on-rewrite no
              
              # 重写触发配置
              auto-aof-rewrite-percentage 100
              auto-aof-rewrite-min-size 64mb
              
              # 加载aof出错如何处理
              aof-load-truncated yes
              
              # 文件重写策略
              aof-rewrite-incrempythonental-fsync yes

              AOF实现步骤

              AOF需要记录Redis的每个写命令,步骤为:

              • 命令追加(append):启AOF持久化功能后,服务器每执行一个写命令,都会把该命令以协议格式先追加到aof_buf缓存区的末尾

              不是直接写入文件,避免每次有命令都直接写入硬盘,减少硬盘IO次数

              文件写入(write),文件同步(sync):何时把aof_buf缓冲区的内容写入保存在AOF文件中,Redis提供了多种策略,appendfsync选项的默认配置为everysec,即每秒执行一次同步

              • appendfsync always:将aof_buf缓冲区的所有内容写入并同步到AOF文件,每个写命令同步写入磁盘
              • appendfsync everysec:将aof_buf缓存区的内容写入AOF文件,每秒同步一次,该操作由一个线程专门负责
              • appendfsync no:将aof_buf缓存区的内容写入AOF文件,什么时候同步由操作系统来决定

              AOF的同步策略是涉及到操作系统的write函数和fsync函数的

              AOF重写

              基本概念

              AOF会记录每个写命令到AOF文件,随着时间越来越长,AOF文件会变得越来越大。

              为了解决AOF文件体积膨胀的问题,Redis提供AOF文件重写机制来对AOF文件进行“瘦身”。

              AOF重写的目的就是减小AOF文件的体积

              Redis通过创建一个新的AOF文件来替换现有的AOF,新旧两个AOF文件保存的数据相同,但新AOF文件没有了冗余命令

              • 时间长了,AOF文件中通常会有一些冗余命令,
              • 比如:过期数据的命令、无效的命令(重复设置、删除)、多个命令可合并为一个命令(批处理命令)。
              • 所以AOF文件是有精简压缩的空间的

              触发方式

              文件重写可分为手动触发和自动触发

              • 手动触发执行bgrewriteaof命令,该命令的执行跟bgsave触发快照时类似的,都是先fork一个子进程做具体的工作
              • 自动触发会根据auto-aof-rewrite-percentage和auto-aof-rewrite-min-size 64mb配置来自动执行bgrewriteaof命令

              重写过程

              AOF重写过程是由后台进程bgrewriteaof来完成的。

              • 主线程fork出后台的bgrewriteaof子进程,fork会把主线程的内存拷贝一份给bgrewriteaof子进程,这里面就包含了数据库的最新数据。
              • 然后,bgrewriteaof子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。
              • 所以aof在重写时,在fork进程时是会阻塞住主线程的

              重写过程总结为:“一个拷贝,两处日志”。在fork出子进程时的拷贝,以及在重写时,如果有新数据写入,主线程就会将命令记录到两个aof日志内存缓冲区中

              • 而在bgrewriteaof子进程完成会日志文件的重写操作后,会提示主线程已经完成重写操作,主线程会将AOF重写缓冲中的命令追加到新的日志文件后面
              • 这时候在高并发的情况下,AOF重写缓冲区积累可能会很大,这样就会造成阻塞,Redis后来通过linux管道技术让aof重写期间就能同时进行回放,这样aof重写结束后只需回放少量剩余的数据即可
              • 最后通过修改文件名的方式,保证文件切换的原子性
              • 在AOF重写日志期间发生宕机的话,因为日志文件还没切换,所以恢复数据时,用的还是旧的日志文件

              重写过程中主线程有哪些地方会被阻塞?

              fork子进程时,需要拷贝虚拟页表,会对主线程阻塞。

              主进程有bigkey写入时,操作系统会创建页面的副本,并拷贝原有的数据,会对主线程阻塞。

              子进程重写日志完成后,主进程追加aof重写缓冲区时会对主线程阻塞

              为什么不复用原AOF日志

              子进程写同一个文件会产生竞争问题,影响父进程的性能。

              如果AOF重写过程中失败了,相当于污染了原本www.devze.com的AOF文件,无法做恢复数据使用

              RDB vs AOF

              维度RDBAOF
              数据安全性低(依赖快照周期)高(可配置秒级同步)
              性能影响低(后台异步)中高(同步写盘/重放命令)
              恢复速度快(直接加载二进制)慢(逐条执行命令)
              文件体积小(压缩存储)大(需重写优化)
              适用场景容灾备份/快速恢复金融级数据安全要求

              Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作

              AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销

              这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单优势, 实际环境中用的很

              如何保证数据一致性

              RDB中的核心思路是Copy-on-Write,来保证在进行快照操作的这段时间,需要压缩写入磁盘上的数据在内存中不会发生变化。

              • 一方面Redis主进程会fork一个新的快照进程专门来做这个事情,这样保证了Redis服务不会停止对客户端包括写请求在内的任何响应
              • 另一方面这段时间发生的数据变化会以副本的方式存放在另一个新的内存区域,待快照操作结束后才会同步到原来的内存区域

              例如:

              • 如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就SzBwioDP会被复制一份,生成该数据的副本。
              • 然后,bgsave 子进程会把这个副本数据写入 RDB 文件,
              • 而在这个过程中,主线程仍然可以直接修改原来的数据。

              总结

              以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

              0

              精彩评论

              暂无评论...
              验证码 换一张
              取 消

              关注公众号