只针对写操作才会持久化

Redis持久化是为了解决内存数据容易丢失的问题。既然是数据恢复,那么恢复的就是数据变化后的状态。而数据只有在写操作之后才有变化。读操作只是查询数据并不会改变数据的状态,所以操作不会被持久化。

RDB(Redis Database)持久化

快照(Snapshotting)持久化,在指定的时间间隔内将内存中的数据写入到磁盘。

RDB持久化的触发方式

手动触发

  • SAVE命令:同步保存操作,会阻塞主线程,知道RDB文件生成完毕。生产环境下不推荐使用。
  • BGSAVE命令:后台异步执行。Redis主线程会fork一个子进程进行RDB文件生成,主线程继续处理客户端响应。只会在fork子进程的时候会有短时的暂停阻塞响应,这是推荐的手动触发的方式。

自动触发

  • redis_conf配置:通过配置save 规则,当在秒内,触发至少写操作时,Redis会自动执行一次BGSAVE操作。

    1
    2
    3
    save 900 1: 900秒内至少有一次key被修改。
    save 300 10: 300秒内至少有个10次key被修改。
    save 60 10000: 60秒内至少有10000次key被修改。
  • FLUSHALL / FLUSHDB命令:执行清除数据库时,如果配置了RDB也会生成一次RDB保存(保存一个空的RDB文件)。

  • SHUTDOWN命令:正常关闭Redis时,如果没有配置AOF,默认会执行一次SAVE命令,生成RDB文件。

  • 主从复制时:当进行全量同步时,主节点会生成RDB文件发送给从节点。

工作原理

  1. Redis主线程接收到RDB的请求(手动或者自动触发)
  2. 主进程fork一个子进程
  3. 子进程遍历Redis内存中的数据将数据写到一个临时的rdb文件中。这个过程中采用了写时复制(copy on write , cow)技术,主进程和子进程同时共享同一个内存页数据,当主进程进行内存修改时,操作系统会复制一个新的内存页使用。fork子进程继续使用旧的内存页数据。
  4. 当子进程写完rdb数据后,用这个临时的rdb文件替换掉原来的dump.rdb文件。
  5. 子进程退出,通知主进程RDB持久化完成。

优点和缺点

优点

二进制文件,仅记录数据结果,恢复速度快,文件紧凑,适合备份

缺点

数据丢失风险:RDB是定时保存的,如果最后一次快照后的数据没有进行保存就宕机,就丢失了最后一次快照后的数据。

适用场景

对数据完整度要求不严格,允许丢失少量数据,用于灾难恢复。


AOF(Append Only File)持久化方式

只追加文件,记录Redis服务器收到的所有的写操作,以文本方式追加到AOF文件中。

工作原理

  1. 命令追加(Append):当Redis执行写操作时,会将执行命令追加到AOF缓冲区(内存)中。
  2. 文件写入(Write):根据AOF配置的规则会将AOF缓冲区中的数据写入到操作系统内核缓冲区。此时还没有写入到磁盘。
  3. 文件同步(Fsync/Sync):根据配置的同步策略,会将操作系统内核缓冲区中的数据写入到磁盘。
  4. 重启加载:默认优先加载AOF文件进行恢复,生成一个伪客户端执行这些命令,就像客户端发送指令到Redis服务器一样,自己给自己发。

appendfsync同步策略:

  • always:每次的写指令都会同步,最安全,但是性能开销大。
  • everysec:每秒调用一次,默认方案,性能较好,可能会丢失1s数据。
  • no:不主动同步,根据操作系统自己同步,性能最优。

AOF重写(Rewrite)

随着 AOF 文件越来越大,Redis 会在满足条件时(例如文件大小达到一定阈值且增量百分比达到预设值)自动触发 BGREWRITEAOF

  • Redis fork 一个子进程。
  • 子进程读取当前内存中的数据。
  • 子进程将这些数据转化为最少的写命令集合,写入一个新的临时 AOF 文件。例如,如果你对 counter 这个 key 做了 1000 次 INCR 操作,最终结果是 1000,那么新的 AOF 文件中可能只会有一个 SET counter 1000 命令。
  • 主进程在重写期间继续将新命令追加到旧的 AOF 文件一个新的 AOF 缓冲区中。
  • 当子进程完成重写后,主进程会将重写期间生成的新命令追加到新的 AOF 文件尾部。
  • 最后,主进程原子性地用新的 AOF 文件替换旧的 AOF 文件。

优缺点

优点

数据完整性高,基本不丢失数据,可读性高。

缺点

  • 文件可能会越来越大,占用存储空间。
  • 恢复速度较慢

适用场景

对数据完整性要求高,不希望丢失数据。


RDB和AOF混合使用持久化方式

这是Redis 4.0及更高版本推荐的持久化方式。它结合了两者的优点,在数据恢复时,速度更快且数据丢失更少。

最佳实践

  • 开启RDB和AOF,并开启混合持久化。
  • 将AOF设置为everysec策略,确保数据丢失最小。
  • RDB可以作为AOF的补充备份,或者用于大规模数据恢复时快速加载初始数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
################################## RDB CONFIGURATION ##################################

# 是否开启 RDB 持久化。通常在开启 AOF 且使用混合持久化时,RDB 可以作为额外的冷备份。
# 如果不希望单独生成 RDB 文件,也可以设置为 "no",因为 AOF 混合模式本身包含了 RDB 部分。
# 但为了更全面的备份策略,建议保留,并根据数据修改频率调整。
save 900 1 # 900秒(15分钟)内至少1个key发生变化则触发BGSAVE
save 300 10 # 300秒(5分钟)内至少10个key发生变化则触发BGSAVE
save 60 10000 # 60秒(1分钟)内至少10000个key发生变化则触发BGSAVE

# 当 RDB 持久化出错时,是否停止写操作。推荐设为 "yes" 以避免数据不一致。
stop-writes-on-bgsave-error yes

# 是否压缩 RDB 文件。推荐 "yes" 以节省磁盘空间,但会增加CPU开销。
rdbcompression yes

# RDB 文件名
dbfilename dump.rdb

# RDB 文件存储路径
dir ./

################################## AOF CONFIGURATION ##################################

# 是否开启 AOF 持久化。必须设置为 "yes" 以使用 AOF 和混合持久化。
appendonly yes

# AOF 文件名
appendfilename "appendonly.aof"

# AOF 同步策略。这是数据安全的关键。
# always: 每次写操作都同步,最安全,但性能最低。
# everysec: 每秒同步一次,推荐且默认。兼顾性能和数据安全,最多丢失1秒数据。
# no: 不同步,完全依赖操作系统,性能最高,但数据丢失风险最大。
appendfsync everysec

# AOF 重写(rewrite)触发条件:
# 当 AOF 文件大小是上次重写后文件大小的百分比。
auto-aof-rewrite-percentage 100 # 当AOF文件大小是上次重写后大小的100%时触发(即翻倍)

# 触发 AOF 重写所需的最小 AOF 文件大小。
auto-aof-rewrite-min-size 64mb # 只有当AOF文件大于64MB时才可能触发重写

# AOF 混合持久化:
# 开启后,AOF 重写时会先写入 RDB 格式的快照,然后追加 AOF 格式的增量命令。
# Redis 4.0 及以上版本引入,强烈推荐开启。
aof-use-rdb-preamble yes

# 当 AOF 重写(BGREWRITEAOF)进行时,新的写命令会先写入内存缓冲区,
# 而不是直接追加到旧的 AOF 文件。当重写完成后,这些命令会被追加到新的 AOF 文件中。
# 此选项是防止 AOF 重写对主进程性能影响过大。
# no-appendfsync-on-rewrite yes # 默认为no,即重写期间仍会进行fsync,但可能会阻塞

################################## GENERAL CONFIGURATION ##################################

# 最大内存限制,达到此限制后,Redis 会根据策略淘汰键。
maxmemory <your_max_memory_limit_here>
maxmemory-policy allkeys-lru # 根据业务选择淘汰策略,allkeys-lru 是常用选择

在生产环境中,通常会同时开启RDB和AOF,以提供最大的数据安全保障。RDB可以用于灾难恢复时的快速全量恢复,而AOF则保证了数据丢失的最小化。

核心流程

无论 AOF 重写是自动触发(根据 auto-aof-rewrite-percentageauto-aof-rewrite-min-size)还是手动触发 (BGREWRITEAOF 命令),其流程大致如下:

  1. fork 子进程
    • Redis 主进程调用 fork() 创建一个 AOF 重写子进程
    • 同样地,写时复制(COW) 机制在这里发挥作用,主进程和子进程一开始共享内存页。
  2. 子进程生成 RDB 部分
    • AOF 重写子进程不会像传统的 AOF 重写那样直接将命令写入。
    • 相反,它会像 RDB 持久化一样,遍历当前 Redis 内存中的所有数据(也就是 fork 瞬间的数据状态)。
    • 然后,将这些数据以RDB 的二进制格式写入到一个临时文件中。这部分是整个混合文件的前缀,被称为 RDB Preamble(RDB 前言)
  3. 主进程记录增量 AOF
    • 在 AOF 重写子进程忙于生成 RDB Preamble 的同时,Redis 主进程继续处理客户端的请求。
    • 所有在重写期间发生的新写操作命令,都会被主进程同时记录到两个地方
      1. 当前的 AOF 缓冲区:这些命令会像往常一样,根据 appendfsync 策略写入到旧的 appendonly.aof 文件中,以确保数据不丢失。
      2. AOF 重写缓冲区:这些命令也会被复制一份,累积到一个专门用于 AOF 重写过程的内存缓冲区中(通常称为 AOF rewrite buffer)。
  4. 子进程追加 AOF 尾部
    • 当 AOF 重写子进程完成 RDB Preamble 的写入后,它会通知主进程。
    • 接着,主进程会将步骤3中累积在 AOF 重写缓冲区里的增量写命令通过管道发送给子进程。
    • 子进程接收到这些增量命令后,会将其以AOF 的文本格式追加到之前写入的 RDB Preamble 文件的末尾。这部分就是混合文件的 AOF Tail(AOF 尾部)
  5. 原子性替换
    • 当子进程完全写入新的混合格式 AOF 文件(包含 RDB Preamble 和 AOF Tail)后,它会通知主进程。
    • 主进程会用这个新的临时文件原子性地替换掉旧的 appendonly.aof 文件
  6. 子进程退出:AOF 重写完成,子进程退出。

因此,混合持久化是 Redis 推荐的生产环境持久化方案,它在性能、数据安全和恢复效率之间取得了最佳平衡。