返回

Redis持久化

Redis 为什么需要持久化

RDB(Redis Database)

RDB 持久化以指定的时间间隔对数据集执行时间点快照(实际上就是记录某一个时间节点的内存数据)。

配置操作

Redis 7.4.2 默认 RDB 参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 1p/1h 或 100p/5m 或 10000p/60s 
save 3600 1 300 100 60 10000

# RDB 快照保存文件名
dbfilename dump.rdb

# RDB 快照保存目录
dir ./

# 在快照写入失败时是否停止写请求
stop-writes-on-bgsave-error yes

# 是否开启 RDB 压缩(LZF压缩算法)
rdbcompression yes

# 是否开启 RDB 数据校验(CRC64算法)
rdbchecksum yes

# 是否删除未启用持久性的实例中复制使用的 RDB 文件
rdb-del-sync-files no

默认情况下,Redis 会将数据集的快照保存在磁盘上一个名为 dump.rdb 的二进制文件中。 你也可以手动调用 SAVE 或 BGSAVE 命令。

  • 执行 save 命令,就会在主线程生成 RDB 文件,由于和执行操作命令在同一个线程,所以如果写入 RDB 文件的时间太长,会阻塞主线程线上禁止使用
  • 执行了 bgsave 命令,会创建一个子进程来生成 RDB 文件,这样可以避免主线程的阻塞

执行 flushall/flushdb 命令也会产生 .rdb 文件,但是该文件中没有任何数据(因为他是在清盘之后才保存的)。在恢复数据时,一定要将服务和备份分机隔离(防止备份的 .rdb 文件被覆盖)。

触发时机

  • 配置文件中默认的快照配置
  • 手动 sava/bgsave 命令
  • 执行 flushall/flushdb 命令
  • 执行 shutdown 且没有设置 AOF 持久化
  • 主从复制,主节点自动触发

优势

  • 适合大规模的数据恢复
  • 按照业务定时备份
  • 对数据完整性和一致性要求不高
  • RDB 文件在内存中加载速度比 AOF 快得多

劣势

  • RDB 会丢失备份间隔时间内的所有数据,也就是说距离上一次备份期间内的所有数据都会被丢失
  • RDB 是全量快照,每次执行都会把所有的数据记录到磁盘中,频繁的磁盘 I/O 可能影响服务器性能
  • RDB 依赖主进程的 fork,在极端形况下内存占用会变为原先的 2 倍。

执行 RDB 快照时能否修改数据

可以,使用写时复制技术

执行 bgsave 命令时,通过 fork() 创建子进程,因此父进程、子进程共享同一片内存数据(两份页表,一份物理内存)。只有当发生数据修改时,才会复制一份新的物理内存(注意此时子进程会将旧的物理内存写入 RDB 文件,而主进程会在新的物理内存中修改数据)。这样就可以避免主线程阻塞。

AOF(Append Only File)

AOF 持久性记录服务器收到的每个写入操作。 这些操作可以在服务器启动时再次重放,重建原始数据集。 命令记录格式与 Redis 协议本身相同。

配置操作

Redis 7.4.2 默认 AOF 参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# AOF 默认关闭
appendonly no

# AOF 文件名
appendfilename "appendonly.aof"

# AOF 保存目录
appenddirname "appendonlydir"

# 回写策略(三种,默认 everysec)
# appendfsync always
appendfsync everysec
# appendfsync no

默认情况下,Redis 会将记录到的命令文件保存在磁盘上一个名为 appendonly.aof 的文件中。 Redis 6 之前只有一个 AOF 文件。Redis 7 之后有三个文件(合并在一个文件中):

  • appendonly.aof.1.base.rdb:基础 AOF,最多只有一个,一般由子进程通过重写产生
  • appendonly.aof.1.incr.aof:增量 AOF,可能存在多个,一般会在 AOF 重写时创建
  • 历史 AOF,每次 AOF 重写完成时,之前的基础 AOF 和增量 AOF 都会编程历史 AOF。Redis 配置里没有,因为它会被自动删除
  • appendonly.aof.manifest:跟踪管理 AOF 文件

工作流程

image-20250117220833281

  1. Client 向 Redis 发送操作命令
  2. 这些命令首先进入 AOF 缓冲区保存(避免频繁的磁盘 I/O 操作)
  3. AOF 根据写回策略将缓冲区命令写入磁盘中
  4. 为了 AOF 文件的膨胀,会进行 AOF 重写压缩文件
  5. Redis 会在服务启动时加载磁盘中的 AOF 文件再次执行这些命令

执行优势

Redis 是先执行写操作命令后,才将该命令记录到 AOF 日志里的,这么做其实有两个好处。

  • 避免额外的检查开销,因为能执行的命令必然是正确的命令
  • 不会阻塞当前写操作命令的执行,因为只有写命令直接成功后才会记录

执行劣势

  • 当 Redis 执行命令后,记录命令前,这个时刻 Redis 服务宕机,那么这个数据就会有丢失的风险
  • 由于 Redis 执行命令和 AOF 写入这两个操作均是在一个线程中完成,那么可能导致下一个命令阻塞

写回策略

上图中第二步和第三步可以再细化为以下几步:

  1. Redis 执行完写命令后,将该命令追加到 server.aoof_buf 缓冲区中
  2. 通过调用系统函数 write(),将缓冲区内数据写入到 AOF 文件中,此时数据并没有写入到硬盘,而是拷贝到了内核缓冲区 page cache
  3. 内核缓冲区将数据写入硬盘

Redis 提供了三种写回策略

  • Always
    • 策略含义:每次写命令执行完后,将 AOF 写回硬盘
    • 实际操作:每次写命令执行完之后立刻执行 fsync() 函数
  • Everysec
    • 策略含义:每次写命令执行完后,先将其写入 AOF 缓冲区,之后每隔一秒将缓冲区写入磁盘
    • 实际操作:每次写命令执行完之后,会创建一个异步进程执行 fsync() 函数
  • No
    • 策略含义:每次写命令执行完后,先将其写入 AOF 缓冲区,之后将缓冲区写入磁盘(由操作系统决定间隔时间)
    • 实际操作:永远不执行 fsync() 函数

小结

写回策略写回时机优点缺点
Always同步写回可靠性高性能开销大
Everysec每秒写回性能、可靠性均衡宕机丢失 1 秒内数据
No由操作系统决定性能高宕机丢失数据多

重写机制

当 AOF 文件的大小(默认64MB)超过所设定的阈值后,Redis 启动 重写机制。由于重写操作十分耗时,所以该过程是由子进程 bgrewriteaof 完成的,有以下两点好处

  • 重写期间避免阻塞主进程
  • 子进程带有主进程的数据副本,如果父子进程任何一方修改内存会触发写时复制机制,确保数据安全。

触发重写机制后,主进程就会创建重写的 AOF 子进程,此时父子进程共享物理内存,重写子进程只会对该内存读取,重写 AOF 子进程会读取数据库里的所有数据,并逐一把内存数据的键值对转换为一条命令,再将命令记录到重回日志(新的 AOF 文件)。

子进程完成 AOF 重写工作后,会向主进程发送一条异步信号。主进程收到信号后首先将 AOF 缓冲区中所有内容追加到新的 AOF 文件中,然后将新的 AOF 文件改名,覆盖掉旧的 AOF 文件。

Licensed under CC BY-NC-SA 4.0
载入天数...载入时分秒...
使用 Hugo 构建
主题 StackJimmy 设计