Redis 数据持久化:RDB和 AOF 有什么区别?

思维导图

本文的思维导图如下:

Redis 持久化相关面试题的思维导图如下:

一、Redis 持久化

Redis 作为缓存,其数据的持久化是怎么做的?

Redis 提供了两种数据持久化的方式:

  1. RDB
  2. AOF

(一)RDB

1. 什么是 RDB?

RDB 全称 Redis Database Backup file(Redis 数据备份文件 ),也被叫做 Redis 数据快照

简单来说 RDB 就是 Redis 的一种数据备份文件 ,++它把内存中的所有数据都记录到磁盘中++。

更专业一点来说 RDB 就是 Redis 的快照式数据备份文件

它会在某个时间点,把内存里的所有数据打包成一个 .rdb 文件保存到磁盘上。

当 Redis 实例故障重启后,可以直接读取这个 RDB 文件,快速恢复数据。

2. RDB 的基本操作

1)主动备份

解释:

  1. save主进程自己亲自干活
    save 的流程是:

    主进程直接把内存写成 RDB 文件,在这期间会阻塞所有客户端命令

  2. bgsave主进程 fork 一个子进程,由子进程专门干活(写 RBD)
    bgsave 的流程是:

    1. 主进程接到 bgsave 命令;
    2. 主进程 fork() 一个子进程;
    3. 主进程继续处理客户端请求(只有在 fork 那一瞬间会有毫秒级抖动);
    4. 子进程负责把当前内存快照写成 RDB 文件

2)自动备份

Redis 默认是开启 RDB 自动备份的, 它会按照 redis.conf 里配置的 save 规则,在满足条件时自动生成 .rdb 快照文件。

redis.conf 里配置的 save 规则格式如下:

解释:

plsql 复制代码
save 900 1      # 15分钟内 ≥1 次修改 → 触发 RDB
save 300 10     # 5分钟内 ≥10 次修改 → 触发 RDB
save 60 10000   # 1分钟内 ≥10000 次修改 → 触发 RDB

它本质是一个"或(OR)关系":只要任意一条满足条件 ,就会触发 bgsave

这是 Redis 的一种 "多级自动快照保险机制":

  • 写得少 → 用 15 分钟兜底
  • 写得多 → 5 分钟甚至 1 分钟就备份一次

这些 save 规则是执行 save 还是 bgsave

Redis 在"自动触发快照"这种场景下,选择的是 bgsave,而不是 save

3. RDB 的执行原理

bgsave 中 RDB 是如何被子进程写到磁盘里的呢?

bgsave 在开始时会 fork 主进程得到子进程,子进程会 共享 主进程的内存数据。

完成 fork 后,子线程读取内存数据并写入 RDB 文件。


子进程如何共享内存呢?

Redis 的主进程通过复制一份自己的页表给子线程。


为什么要通过复制页表呢?什么是页表呢?

这个问题得回到 ++Redis 的进程都是如何访问物理内存++上来。

因为 Redis 的进程没办法直接操作 操作系统的物理内存,只能操作 操作系统提供给它们的虚拟内存,具体来说就是通过页表来操作。

页表:记录虚拟地址和物理地址的映射关系。

这样,Redis 就能通过页表来关联到物理内存,从而实现在内存读写数据。


两个进程异步读写共享内存,如何避免脏读呢?

问题描述: 子进程在写 RDB 的时候,需要读取共享内存,这个过程中主进程也在继续处理客户端请求,可能会修改共享内存的数据,这样 RDB 就会出现脏数据,那如何避免"RDB 脏写"问题呢?

解决方案: 操作系统的 fork 机制中有一种叫做 读写复制(Copy-On-Write,COW)

什么是读写复制?

操作系统在实现 fork() 时"原生自带"的一种内存优化机制:

多个进程"先共享同一份数据",只有在"真的要修改时",才复制一份出来。

1)fork 时:

  • 父进程和子进程 先共享同一块物理内存
  • 内存页在页表中被标记为 只读(read-only)

2)读操作:

  • 父子进程都直接读这块共享内存

3)写操作:

  • 只要某个进程要修改:
    • CPU 发现这是只读页
    • 触发异常
    • 操作系统 复制一份新的内存页
    • 然后再让这个进程修改自己的副本

Redis 的主进程在调用 fork 的时候,操作系统就会在页表上把共享内存标记为 read-only

  • 当主进程执行读操作时,可以读取共享内存;
  • 当主进程执行写操作时,需要拷贝一份数据,才能执行写操作。

Redis 里一次完整的bgsave流程如下:

plsql 复制代码
客户端发送 BGSAVE
        ↓
Redis 主进程调用 fork()
        ↓
操作系统创建子进程(共享内存页:主线程把页表拷贝给子进程)
        ↓
子进程:遍历内存 → 写 dump.rdb 文件,把 RDB 写入 磁盘中
        ↓
主进程:继续处理客户端请求
        ↓
子进程写完 → 发送信号给父进程
        ↓
父进程替换旧 RDB 文件

(二)AOF

1. 什么是 AOF?

AOF 全称为 Append Only File(追加文件)。

Redis 处理的每一个写命令都会记录在 AOF 文件,可以看做是命令日志文件

2. AOF 的基本操作

1)手动开启 AOF

在 redis.conf 配置文件中,AOF 默认是关闭的,需要将appendonly no 修改为 appendonly yes来开启 AOF:

2)设置刷盘策略

什么是 AOF 的刷盘策略?

AOF 刷盘策略是控制 AOF 缓冲区里的数据多久同步到磁盘一次。

每次执行写命令,比如 set num 123,Redis 会做以下三步:

① 执行命令,修改内存数据

② 把这条命令追加写入 AOF 缓冲区

③ 什么时候真正写进磁盘?→ 由 appendfsync 决定

也就是说:

  • 记录命令:几乎每次都会发生
  • 刷盘落盘:由策略控制

AOF 是"先记日志,再按策略刷盘",刷盘策略管的是"落盘频率"。

AOF 的刷盘策略也可以通过修改 redis.conf 配置文件来设置:

AOF 有三种刷盘策略:

我们一般选择 everysec,性能适中,风险适中。

3)设置 AOF 重写

AOF 的缺点

  1. 因为是 AOF 记录的是命令, RDB 记录的是数据 → 所以 AOF 文件会比 RDB 文件大的多。
  2. 而且 AOF 会记录对同一个 key 的多次写操作,但只有最后一次写操作才是有意义的。

解决方案 ------ bgrewriteaof命令

  1. 手动触发 AOF 重写
    我们可以在 redis-cli 里手动执行bgrewriteaof命令,立即 fork 子进程,在后台重写 AOF 文件,以此用最少的命令达到相同效果。
    示例: 左边是原始 AOF(命令"流水账")→ 右边是重写后的 AOF(只保留"最终状态")
命令 含义
set num 123 把 key = num 的值设为 123
set name jack 把 key = name 的值设为 jack
set num 666 再次覆盖 key = num 的值,变成 666
  • numset 了两次
  • 123 这个值 已经变成"历史垃圾数据"

  1. 自动触发 AOF 重写
    我们也可以在 redis.conf 配置文件里配置 AOF 重写的策略(触发阈值)。
    这样 Redis 就可以在触发某个阈值的时候,自动去重写 AOF 文件。

    AOF 只有在"体积增长够多 + 文件本身够大"这两个条件同时满足时,才会自动触发重写。

(三)RDB 和 AOF 对比

RDB 和 AOF 是 Redis 提供的两套不同的数据持久化方案。

名称 本质身份
RDB 一种持久化方式(快照持久化)
AOF 一种持久化方式(日志持久化)

它们解决的是同一个问题:如何保证内存数据在 Redis 实例宕机后还能恢复?

它们最终会都会各自产生对应的磁盘文件。

持久化方式 生成的文件
RDB dump.rdb(二进制快照文件)
AOF appendonly.aof(命令日志文件)

RDB 和 AOF 各有优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。

二、相关面试题

什么是 Redis 的持久化?

Redis 的持久化机制,是指 Redis 通过 RDB 快照AOF 日志 的方式,把内存中的数据同步保存到磁盘文件中,当 Redis 重启时,可以通过这些文件把数据恢复回来,从而保证数据不因宕机而丢失。

为什么 Redis 一定要做持久化?

因为:Redis 默认是 内存数据库

如果:服务器断电、进程崩溃

  • 不做持久化 → 数据全部清空 ❌
  • 做了持久化 → 可以从磁盘恢复 ✅

Redis 作缓存,数据的持久化是怎么做的?

Redis 中提供了两种数据持久化方式:一是 RDB ,二是 AOF

RDB 和 AOF 有什么区别?

RDB
定义: RDB 是通过生成内存数据快照来做持久化的,它会把某一时刻 Redis 内存中的所有数据一次性写入磁盘。

优点: RDB 文件体积小、恢复快。

缺点: 但缺点是如果 Redis 异常宕机,可能会丢失最近一次快照之后的数据


AOF
定义: AOF 是通过追加写命令日志来做持久化的。

优点: 每一条写命令都会被记录下来,因此数据安全性更高。

缺点: 但缺点是 AOF 文件体积更大、恢复时需要重放命令,所以恢复速度相对更慢。

当 Redis 宕机重启时,会从 AOF 日志中再次执行一遍命令来恢复数据。


实际生产

我们在实际生产中通常会同时开启 RDB 和 AOF。

用 RDB 做冷备和快速恢复,用 AOF 保证数据安全。

这两种方式,哪种恢复得比较快?

RBD 快。

因为 RDB 是二进制文件,它在保存的时候体积也是比较小的,所以它恢复的比较快。

但是它有可能会丢数据,所以我们通常在项目中也会使用 AOF 来恢复数据。

虽然 AOF 恢复的速度慢一些,但是它丢数据的风险要小很多。

而且在 AOF 文件中可以设置刷盘策略,我们可以设置每秒批量写入一次命令。

相关推荐
夏贰四11 分钟前
中小企业搭建业务中台如何控成本?业务中台轻量化落地分几步实施?
数据库·业务中台
天使day25 分钟前
FastAPI快速入门
python·fastapi
databook31 分钟前
用相关性分析消除“冗余特征”
python·机器学习·scikit-learn
林焱RPA39 分钟前
影刀RPA200篇纪念版:最实用的20个自动化场景大盘点
数据库
名字还没想好☜40 分钟前
Go 的 time.After 在 select 循环里内存泄漏:定时器堆积原理与 timer.Reset 正确姿势
java·数据库·golang·go·goroutine
gwf21643 分钟前
SSD读写速度深度解析:顺序读写vs随机读写、IOPS、延迟,你的硬盘性能到底怎么看?
git·嵌入式硬件·缓存·github·智能硬件
圆山猫1 小时前
[Virtualization](三):RISC-V H-extension 与 Guest 执行模式
android·java·risc-v
caishenzhibiao1 小时前
期货先行者主图 同花顺期货通指标
java·c语言·c#
幻想时空1 小时前
地图数据采集
python
梦想不只是梦与想1 小时前
Python 中的类型判断方法
python·type·isinstance