Redis之持久化

1.前言

Redis⽀持RDB和AOF两种持久化机制,持久化功能有效地避免因进程退出造成数据丢失问题,

当下次重启时利⽤之前持久化的⽂件即可实现数据恢复。本文内容:

• 介绍RDB、AOF的配置和运⾏流程,以及控制持久化的命令,如bgsave和bgrewriteaof。

• 对常⻅持久化问题进⾏分析定位和优化。

2.RDB

RDB持久化是把当前进程数据⽣成快照保存到硬盘的过程,触发RDB持久化过程分为⼿动触发和⾃动触发。

2.1.1触发机制

手动触发:

⼿动触发分别对应save和bgsave命令:

• save命令:阻塞当前Redis服务器,直到RDB过程完成为⽌,对于内存⽐较⼤的实例造成⻓时间

阻塞,基本不采⽤。

• bgsave命令:Redis进程执⾏fork操作创建⼦进程,RDB持久化过程由⼦进程负责,完成后⾃动

结束。阻塞只发⽣在fork阶段,⼀般时间很短。

Redis内部的所有涉及RDB的操作都采⽤类似bgsave的⽅式。


自动触发:

除了⼿动触发之外,Redis 运⾏⾃动触发 RDB 持久化机制,这个触发机制才是在实战中有价值的。

  1. 使⽤ save 配置。如 "save m n" 表⽰ m 秒内数据集发⽣了 n 次修改,⾃动 RDB 持久化。
  2. 从节点进⾏全量复制操作时,主节点⾃动进⾏ RDB 持久化,随后将 RDB ⽂件内容发送给从结点。
  3. 执⾏ shutdown 命令关闭 Redis 时,执⾏ RDB 持久化。

2.1.2 流程说明

bgsave 是主流的 RDB 持久化⽅式,下⾯根据图了解它的运作流程。

  1. 执⾏ bgsave 命令,Redis ⽗进程判断当前进是否存在其他正在执⾏的⼦进程,如 RDB/AOF ⼦进 程,如果存在 bgsave 命令直接返回。
  2. ⽗进程执⾏ fork 创建⼦进程,fork 过程中⽗进程会阻塞,通过 info stats 命令查看
    latest_fork_usec 选项,可以获取最近⼀次 fork 操作的耗时,单位为微秒。
  3. ⽗进程 fork 完成后,bgsave 命令返回 "Background saving started" 信息并不再阻塞⽗进程,可
    以继续响应其他命令。
  4. ⼦进程创建 RDB ⽂件,根据⽗进程内存⽣成临时快照⽂件,完成后对原有⽂件进⾏原⼦替换。执 ⾏ lastsave 命令可以获取最后⼀次⽣成 RDB 的时间,对应 info 统计的 rdb_last_save_time 选
    项。
  5. 进程发送信号给⽗进程表⽰完成,⽗进程更新统计信息。

2.1.3 RDB ⽂件的处理

保存:RDB ⽂件保存再 dir 配置指定的⽬录(默认 /var/lib/redis/)下,⽂件名通过 dbfilename
配置(默认 dump.rdb)指定。可以通过执⾏ config set dir {newDir} 和 config set dbfilename
{newFilename} 运⾏期间动态执⾏,当下次运⾏时 RDB ⽂件会保存到新⽬录。
压缩:Redis 默认采⽤ LZF 算法对⽣成的 RDB ⽂件做压缩处理,压缩后的⽂件远远⼩于内存⼤
⼩,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。
(虽然压缩 RDB 会消耗 CPU,但可以⼤幅降低⽂件的体积,⽅便保存到硬盘或通过⽹络发送到
从节点,因此建议开启。)
校验:如果 Redis 启动时加载到损坏的 RDB ⽂件会拒绝启动。这时可以使⽤ Redis 提供的 redis
check-dump ⼯具检测 RDB ⽂件并获取对应的错误报告。

2.1.4 RDB 的优缺点

• RDB 是⼀个紧凑压缩的⼆进制⽂件,代表 Redis 在某个时间点上的数据快照。⾮常适⽤于备份,全量复制等场景。⽐如每 6 ⼩时执⾏ bgsave 备份,并把 RDB ⽂件复制到远程机器或者⽂件系统中 (如 hdfs)⽤于灾备。
• Redis 加载 RDB 恢复数据远远快于 AOF 的⽅式。
• RDB ⽅式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运⾏都要执⾏ fork 创建⼦进 程,属于重量级操作,频繁执⾏成本过⾼。
• RDB ⽂件使⽤特定⼆进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有⻛
险。

3.2 AOF

AOF(Append Only File)持久化:以独⽴⽇志的⽅式记录每次写命令,重启时再重新执⾏ AOF
⽂件中的命令达到恢复数据的⽬的。AOF 的主要作⽤是解决了数据持久化的实时性,⽬前已经是
Redis 持久化的主流⽅式。理解掌握好 AOF 持久化机制对我们兼顾数据安全性和性能⾮常有帮助。

3.2.1 使⽤ AOF

开启 AOF 功能需要设置配置:appendonly yes,默认不开启。AOF ⽂件名通过
appendfilename 配置(默认是 appendonly.aof)设置。保存⽬录同 RDB 持久化⽅式⼀致,通过 dir 配置指定。AOF 的⼯作流程操作:命令写⼊(append)、⽂件同步(sync)、⽂件重写
(rewrite)、重启加载(load)。

  1. 所有的写⼊命令会追加到 aof_buf(缓冲区)中。
  2. AOF 缓冲区根据对应的策略向硬盘做同步操作。
  3. 随着 AOF ⽂件越来越⼤,需要定期对 AOF ⽂件进⾏重写,达到压缩的⽬的。
  4. 当 Redis 服务器启动时,可以加载 AOF ⽂件进⾏数据恢复。

3.2.2 命令写⼊

AOF 命令写⼊的内容直接是⽂本协议格式。例如 set hello world 这条命令,在 AOF 缓冲区会追加如下 ⽂本:

复制代码
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n

此处遵守 Redis 格式协议,Redis 选择⽂本协议可能的原因:⽂本协议具备较好的兼容性;实现简单; 具备可读性.
**AOF 过程中为什么需要 aof_buf 这个缓冲区?**Redis 使⽤单线程响应命令,如果每次写 AOF ⽂件都直接同步硬盘,性能从内存的读写变成 IO 读写,必然会下降。先写⼊缓冲区可以有效减少 IO 次数,同 时,Redis 还可以提供多种缓冲区同步策略,让⽤⼾根据⾃⼰的需求做出合理的平衡。

3.2.3 ⽂件同步

Redis 提供了多种 AOF 缓冲区同步⽂件策略,由参数 appendfsync 控制,不同值的含义如下
always:命令写⼊ aof_buf 后调⽤ fsync 同步,完成后返回
everysec: 命令写⼊aof_buf 后只执⾏ write 操作,不进⾏ fsync。每秒由同步线程进⾏ fsync。

no : 命令写⼊ aof_buf 后只执⾏ write 操作,由 OS 控制 fsync 频率。
系统调⽤ write 和 fsync 说明:
• write 操作会触发延迟写(delayed write)机制。Linux 在内核提供⻚缓冲区⽤来提供硬盘 IO 性
能。write 操作在写⼊系统缓冲区后⽴即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区
⻚空间写满或达到特定时间周期。同步⽂件之前,如果此时系统故障宕机,缓冲区内数据将丢失。
• Fsync 针对单个⽂件操作,做强制硬盘同步,fsync 将阻塞直到数据写⼊到硬盘。
• 配置为 always 时,每次写⼊都要同步 AOF ⽂件,性能很差,在⼀般的 SATA 硬盘上,只能⽀持⼤ 约⼏百 TPS 写⼊。除⾮是⾮常重要的数据,否则不建议配置。
• 配置为 no 时,由于操作系统同步策略不可控,虽然提⾼了性能,但数据丢失⻛险⼤增,除⾮数据 重要程度很低,⼀般不建议配置。
• 配置为 everysec,是默认配置,也是推荐配置,兼顾了数据安全性和性能。理论上最多丢失 1 秒的 数据。

3.2.4 重写机制

随着命令不断写⼊ AOF,⽂件会越来越⼤,为了解决这个问题,Redis 引⼊ AOF 重写机制压缩⽂
件体积。AOF ⽂件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF ⽂件。
重写后的 AOF 为什么可以变⼩?有如下原因:
• 进程内已超时的数据不再写⼊⽂件。
• 旧的 AOF 中的⽆效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版
本。
• 多条写操作合并为⼀条,例如 lpush list a、lpush list b、lpush list 从可以合并为 lpush list a b
c。 较⼩的 AOF ⽂件⼀⽅⾯降低了硬盘空间占⽤,⼀⽅⾯可以提升启动 Redis 时数据恢复的速度。 AOF 重写过程可以⼿动触发和⾃动触发:
• ⼿动触发:调⽤ bgrewriteaof 命令。
• ⾃动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定⾃动触发时
机。 ◦ auto-aof-rewrite-min-size:表⽰触发重写时 AOF 的最⼩⽂件⼤⼩,默认为 64MB。
◦ auto-aof-rewrite-percentage:代表当前 AOF 占⽤⼤⼩相⽐较上次重写时增加的⽐例。
流程如下

  1. 执⾏ AOF 重写请求。
    如果当前进程正在执⾏ AOF 重写,请求不执⾏。如果当前进程正在执⾏ bgsave 操作,重写命令
    延迟到 bgsave 完成之后再执⾏。
  2. ⽗进程执⾏ fork 创建⼦进程。
  3. 重写
    a. 主进程 fork 之后,继续响应其他命令。所有修改操作写⼊ AOF 缓冲区并根据 appendfsync 策
    略同步到硬盘,保证旧 AOF ⽂件机制正确。
    b. ⼦进程只有 fork 之前的所有内存信息,⽗进程中需要将 fork 之后这段时间的修改操作写⼊
    AOF 重写缓冲区中。
  4. ⼦进程根据内存快照,将命令合并到新的 AOF ⽂件中。
  5. ⼦进程完成重写
    a. 新⽂件写⼊后,⼦进程发送信号给⽗进程。
    b. ⽗进程把 AOF重写缓冲区内临时保存的命令追加到新 AOF ⽂件中。
    c. ⽤新 AOF ⽂件替换⽼ AOF ⽂件。

3.2.5 启动时数据恢复

当 Redis 启动时,会根据 RDB 和 AOF ⽂件的内容,进⾏数据恢复

4.混合持久化(RDB + AOF)

从 Redis 4.0 开始,支持混合持久化模式。在这种模式下,Redis 会在 AOF 重写时,将重写时刻之前的数据以 RDB 的形式写入 AOF 文件,而之后的写命令仍然以 AOF 的方式追加到文件中。这样既结合了 RDB 持久化恢复速度快的优点,又保留了 AOF 持久化数据安全性高的特点。要开启混合持久化,只需在 redis.conf 配置文件中设置 aof-use-rdb-preamble yes

5. 总结

  1. Redis 提供了两种持久化⽅案:RDB 和 AOF。
  2. RDB 视为内存的快照,产⽣的内容更为紧凑,占⽤空间较⼩,恢复时速度更快。但产⽣ RDB 的开 销较⼤,不适合进⾏实时持久化,⼀般⽤于冷备和主从复制。
  3. AOF 视为对修改命令保存,在恢复时需要重放命令。并且有重写机制来定期压缩 AOF ⽂件。
  4. RDB 和 AOF 都使⽤ fork 创建⼦进程,利⽤ Linux ⼦进程拥有⽗进程内存快照的特点进⾏持久化, 尽可能不影响主进程继续处理后续命令。
相关推荐
数据雕塑家几秒前
数据库 + Grafana 可视化配置指南:从数据源连接到第一个仪表盘
数据库·grafana
源图客11 分钟前
Linux系统部署Postgres数据库(ubuntu22.04)
linux·运维·数据库
minebmw711 分钟前
Oracle 19.29 中 ORA-00600 [4000] 错误完全解析
数据库·oracle
编程经验分享11 分钟前
Windows 安装 PostgreSQL 并安装 vector 扩展
数据库·postgresql
ZPC821012 分钟前
moveit servo 发指令给real arm
java·前端·数据库
企微增长观察12 分钟前
企业微信怎么注册?2026年完整注册流程
java·人工智能·企业微信
身如柳絮随风扬18 分钟前
Redis 如何统计独立用户访问量?
redis
小草儿79918 分钟前
gbase8s之系统表sysprocedures
数据库
爱莉希雅&&&20 分钟前
MySQL 高可用实战:PXC + HAProxy + Keepalived 完整版笔记
运维·数据库·mysql·haproxy·数据库同步·pxc
2301_7641505620 分钟前
Redis如何控制只读从库的安全_配置replica-read-only防止从节点数据被意外篡改
jvm·数据库·python