Redis持久化机制(RDB AOF)
1. RDB
RDB 持久化是把当前进程数据生成快照保存到硬盘的过程,触发 RDB 持久化过程分为手动触发和 自动触发,存储的是二进制数据。
1.1 手动触发
使用 save 和 bgsave 命令触发:
- save:Redis服务主进程阻塞式执行持久化操作,直到RDB过程结束,在此期间 Redis 服务端无法执行客户端的命令,持久化数据量大的情况下,会导致主进程长时间阻塞,使用较少;
- bgsave:后台执行持久化操作,Redis主进程使用 fork 创建子进程,RDB持久化过程由子进程负责执行,阻塞时间较短,只发生在fork阶段;
1.2 自动触发
- 自动触发在 Redis 配置文件 redis.conf 中进行配置, 比如:如 "save m n" 表示 m 秒内数据集发生了 n 次修改,自动 RDB 持久化。
- 从节点进行全量复制操作时,主节点⾃动进行 RDB 持久化,随后将 RDB ⽂件内容发送给从结点。
- 执行 shutdown 命令关闭 Redis 时,也会执行RDB 持久化。
1.3 持久化流程
RDB 是快照式的数据保存,常见的持久化操作都是在 后台进行的(bgsave)流程如下:
- 检查是否已有持久化进程运行,如果有就直接返回;
- Redis 主进程调用
fork()
创建子进程,fork 过程会短暂阻塞主线程(阻塞时间取决于内存大小和系统性能),且由于 父进程创建的子进程和父进程共享数据,详细介绍可见【Linux进程】进程地址空间-CSDN博客 - 父进程 fork 完成后,bgsave 命令返回 "Background saving started" 信息并不再阻塞父进程,可以继续响应其他命令。
- 子进程创建 RDB ⽂件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。
- 进程发送信号给父进程示完成,父进程更新统计信息
1.4 RDB文件
RDB 文件默认在 /var/lib/redis/ 下,文件名通过 dbfilename 配置(默认为 dump.rdb)指定;config set dir {newDir} 和 config set dbfilename {newFilename} 运行期间动态执行,当下次运行时 RDB 文件会保存到新目录
Redis 默认采⽤ LZF 算法对生成的 RDB ⽂件做压缩处理,压缩后的⽂件远远小于内存大小,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。
注意:如果 Redis 启动时加载到损坏的 RDB 文件会拒绝启动。这时可以使用 Redis 提供的 redischeck-dump ⼯具检测 RDB 文件并获取对应的错误报告。
1.5 优缺点
优点:
- RDB 是⼀个紧凑压缩的⼆进制⽂件,存储 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景;
- 数据恢复速度比 AOF 快;
缺点:
- 无法实时持久化(每次都会fork创建子进程,该操作属于重量级操作,频繁创建会严重影响性能);
- RDB 文件使用特定⼆进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有风险。
2. AOF
AOF(Append Only File)持久化:以独立日志的方式记录每次的写命令,重启时再重新执行 AOF 文件中的命令达到恢复数据的目的。AOF 的主要作用是解决了数据持久化的实时性,目前已经是 Redis 持久化的主流方式。
写入的数据可读性也相对较好,比如:set hello world
那么在文件中就会追加以下文本:
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
2.1 配置 AOF
开启 AOF 功能需要设置配置:appendonly yes,默认不开启。AOF 文件名通过 appendfilename 配置(默认是 appendonly.aof)设置。保存目录同 RDB 持久化方式⼀致,通过 dir 配置指定;
2.2 工作流程
1. 所有的写入命令会追加到 aof_buf(缓冲区)中。
2. AOF 缓冲区根据对应的策略向硬盘做同步操作。
3. 随着 AOF文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
4. 当 Redis 服务器启动时,可以加载 AOF 文件进行数据恢复。
2.3 文件同步
由于存在缓冲区的缘故,对于缓冲区同步到文件主要分为三种策略:
可配置值 | 说明 | 数据安全性 | 性能影响 | 适用场景 |
---|---|---|---|---|
always | 每次写入命令后立即调用 | 最高 | 性能最低(频繁磁盘 I/O) | 对数据一致性要求极高的场景(如金融交易) |
everysec | 命令先写入内存缓冲区( | 中等 | 性能与安全的平衡(推荐默认值) | 大多数生产环境 |
no | 命令写入 | 最低 | 性能最高(但可能丢失更多数据) | 可容忍少量数据丢失的高吞吐场景 |
write 和 fsync说明:
write:write会触发操作系统的延迟写机制,write 操作在写入系统缓冲区后就会立即返回;同步到硬盘操作依赖于系统调度机制;如果数据在操作系统缓冲区内还没落盘,此时发生断电或系统宕机,那么缓冲区数据就会丢失;
fsync:针对单个文件操作,做强制硬盘同步,fsync 将阻塞直到数据写入到硬盘;
2.4 重写机制
随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引⼊ AOF 重写机制压缩⽂ 件体积。
为什么会越来越大?比如:
set k1 v1
set k2 v2
del k1
数据实际只存储了 k2 - v2,但存储了三条命令;重写机制可以认为是对 AOF 文件的整理;比如:
- 进程内已超时的数据不再写入文件。
- 旧的 AOF 中的无效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版 本。
- 多条写操作合并为⼀条,例如 lpush list a、lpush list b、lpush list c 可以合并为 lpush list a b c。
AOF 重写过程可以手动动触发和自动触发:
- 手动触发:调用 bgrewriteaof 命令。
- 自动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定⾃动触发时机
auto-aof-rewrite-min-size:表示触发重写时 AOF 的阈值,默认为 64MB。
auto-aof-rewrite-percentage:代表当前 AOF 占用大小相比较上次重写时增加的比例。
2.5 重写流程
1. 执行重写请求,如果当前进程正在执行 AOF 重写,请求不执行。如果当前进程正在执行 bgsave 操作,重写命令延迟到 bgsave 完成之后再执行。
2. 父进程执行 fork 创建子进程
3. 重写
3.1 主进程 fork 之后继续响应其他命令,后续所有修改操作会被记录到 aof_buf 中,根据策略进行落盘;
3.2 子进程只有fork之前的所有内存数据,在子进程重写的期间,父进程需要将修改操作写入 AOF 重写缓冲区中;
4. 子进程根据内存快照,读取内存中数据,整理后写入到新的AOF文件中;
5. 完成重写,进行AOF文件替换
5.1 新文件写入后,子进程发送信号给父进程。
5.2 父进程把 AOF 重写缓冲区内临时保存的命令追加到新 AOF ⽂件中。
5.3 用新 AOF 文件替换旧 AOF 文件。
3. 启动时数据恢复
当 Redis 启动时,会根据 RDB 和 AOF 文件的内容,进行数据恢复;
当 Redis 重启时,如果 AOF 文件和 RDB 文件同时存在,Redis 会优先使用 AOF 文件进行数据恢复;
步骤 | 行为 |
---|---|
检查 AOF 是否启用 | 如果 |
AOF 文件不存在/损坏 | 如果 AOF 文件不可用(如文件损坏),则尝试加载 RDB 文件作为备用恢复。 |
AOF 和 RDB 均未启用 | 启动一个空数据集(无持久化数据)。 |