文章目录
- 1.引言
- 2.认识持久化
- [3. RDB 持久化:定期生成内存快照](#3. RDB 持久化:定期生成内存快照)
-
- [3.1 RDB 的触发方式:手动与自动](#3.1 RDB 的触发方式:手动与自动)
- [3.2 rbd效果演示](#3.2 rbd效果演示)
- [3.3 rdb小结](#3.3 rdb小结)
- [4.AOF 持久化:实时记录操作日志](#4.AOF 持久化:实时记录操作日志)
-
- [4.1 AOF 的开启与配置](#4.1 AOF 的开启与配置)
- [4.2 AOF 的核心:缓冲区刷新策略](#4.2 AOF 的核心:缓冲区刷新策略)
- [4.3 重写机制(瘦身 AOF 文件)](#4.3 重写机制(瘦身 AOF 文件))
- 5.混合持久化
- 6.小结
1.引言
Redis 作为内存数据库,数据默认存储在内存中 ------ 一旦服务器重启、断电或崩溃,内存数据会全部丢失。为解决这一问题,Redis 设计了两种核心持久化方案:RDB(快照持久化)和 AOF(日志持久化),后续又推出 "混合持久化" 结合两者优势。本文将从原理、配置、操作到优缺点对比,全面解析 Redis 持久化机制,帮你理解 "如何在性能与数据安全性之间找到平衡"。
2.认识持久化
首先明确持久化的本质 ------ 将 Redis 内存中的数据定期或实时写入磁盘,确保 "服务器重启后,能从磁盘文件恢复数据",对应 MySQL 事务的 "持久性(Durability)" 特性。、
持久性--》重启主机后,数据是否存在。
存储在磁盘上--》持久
存储在内存上--》不持久
redis 是一个内存数据库,把数据存储在内存上的。
为了保证持久性,也会把数据存储在磁盘上。不过读取数据依旧是在内存,磁盘的数据只是在redis重启时用来恢复内存中的数据的。
插入数据时--》写入内存&磁盘
读取数据时--》从内存中读取
重启redis时--》从磁盘加载数据到内存
(代价是用了更多的空间)
写入磁盘有不同的策略,可能导致内存和磁盘中的数据有小概率存在差异。
redis持久化策略
1)RDB ----》redis database (定期备份)
2)AOF ----》 Append Only File (实时备份)
3. RDB 持久化:定期生成内存快照
RDB定期把redis内存中的所有数据,写入磁盘中,生成一个"快照"。后续redis一旦重启了,就会根据刚才的"快照" 把内存中的数据恢复。
3.1 RDB 的触发方式:手动与自动
手动触发:适合临时备份
save命令:同步执行快照生成,期间会阻塞 Redis(无法处理其他客户端请求),仅适合测试环境,生产环境严禁使用;
bash
127.0.0.1:6379> save # 阻塞Redis,直到快照生成完成
OK
bgsave命令:异步执行快照生成(通过 fork 创建子进程),父进程继续处理客户端请求,无阻塞风险,是生产环境常用方式;
bash
127.0.0.1:6379> bgsave # 立即返回OK,子进程后台生成快照
Background saving started
自动触发
在redis配置文件中,设置redis多久/产生多少修改 后触发

60min内修改1次--》快照
5min内修改100次--》快照
60s内修改10000次 ---》快照
可以修改上述数据,不过生成rdb快照成本较高,所以修改要保证操作执行不能太频繁。
正是因为rdb生成的不能太频繁,所以快照里的数据 和 实时数据 可能存在偏差。
如果在间隔(60s)内,redis收到大量数据 导致 服务器挂了,就会丢失这60s的数据。

- 先判断是否有其他进程正在执行bgsave,有则直接返回
- 没有就通过fork创建子进程,执行bgsave
- 子进程负责写文件,生成快照。父进程继续接收客户端其他请求
- 子进程完成持久化后,通知父进程,父进程更新统计信息后,回收子进程
子进程生成快照时,会生成rdb文件,是放在redis的工作目录中的。
在redis配置文件中,可以设置
后续redis重启,就会尝试加载这个rdb文件
当执行 生成rdb镜像 操作时,会先把生成的快照数据保存到一个临时文件中,当这个快照文件生成完毕后,再删除之前的rdb文件,把新删除的临时rdb文件改成 dump.rdb。
---》 自始至终,rdb文件都只有一个
3.2 rbd效果演示
redis的工作目录
手动执行(一般不执行save)
插入数据进行写快照操作后,rdb文件发生变化
之后重启redis,内存中就会加载rdb文件中的内容,恢复之前的状态
插入新的key,不手动执行bgsave
除了配置的自动触发规则,当正常退出redis服务器时,也会触发rdb操作。
如果是异常重启(kill -9 或者 服务器断电)此时redis服务器来不及生成rdb,内存中尚未保存的数据就会消失。

观察rdb文件的替换
bgsave流程是创建子进程,子进程完成持久化操作,把数据写入新的文件,然后用新文件代替旧文件。(如果直接使用save则不会触发 子进程&文件替换 逻辑,会直接在当前进程中写入数据)
不过子进程完成持久化的操作不好观察,新旧文件替换比较好观察。
可以使用Linux 的 stat命令,查看文件的inode编号,来观察新旧文件的替换。

Linux文件系统:
超级块(存放管理信息)
inode区(存放inode节点,每个文件都会分配一个innode 数据结构,包含文件的各种元数据)
block区 (存放 文件 的数据内容)
通过配置自动生成rdb快照

修改配置后要重启redis服务器才能生效。想要立刻生效也可以通过命令的方式来修改
bash
CONFIG SET save "60 2"

save " " 关闭自动生成快照
手动改坏rdb文件
手动改坏rdb文件(打开redis.conf,手动改)
要通过kill -9 干掉进程,不能直接重启,因为正常重启在关闭前会生成快照。
改坏文件末尾--》对redis重启没什么影响,只是最近保存的数据会丢失。
改坏中间的文件--》发现redis重启不了。
当redis挂了,看看redis的日志,看看发生了什么
在rdb恢复过程中出现问题。
rdb是二进制文件,直接把坏的rdb文件给redis服务器去使用,得到的结果是不可预期的。
可能服务器正常启动,得到的数据可能对 可能错
也可能redis服务器启动失败。
可以通过redis通过的rdb检查工具,检查rdb文件格式是否符合要求

可以看到,这是一个软链接,redis服务器相当于 rdb检查工具的快捷方式。
运行的时候,通过加入选项来以检查工具的方式运行。不加选项就是启动redis服务器。

可以看到检测结果,EOF:end of File,读取文件末尾时遇到问题--》rdb文件损坏
3.3 rdb小结
- RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每 6 小时执行bgsave 备份,并把 RDB 文件复制到远程机器或者文件系统中(如 hdfs)用于灾备。
- Redis 加载 RDB 恢复数据远远快于 AOF 的方式。
- RDB 方式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运行都要执行 fork创建子进程,属于重量级操作,频繁执行成本过高。
- RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有风险。
4.AOF 持久化:实时记录操作日志
AOF 是 Redis 的 "实时持久化" 方案,核心是 "将每一条修改数据的命令(如set、hset)以文本格式追加到 AOF 文件中",类似 MySQL 的 binlog,确保 "每一条命令都不丢失"。
4.1 AOF 的开启与配置
默认情况下 AOF 是关闭的,需修改redis.conf开启:
bash
# 开启AOF(默认no,改为yes)
appendonly yes
# AOF文件名(默认appendonly.aof)
appendfilename "appendonly.aof"
# AOF文件存储路径(与RDB相同,默认/var/lib/redis)
dir /var/lib/redis
4.2 AOF 的核心:缓冲区刷新策略
AOF 并非 "每条命令立即写入磁盘",而是先写入 "内存缓冲区(aof_buf)",再按配置的 "刷新策略" 将缓冲区数据同步到磁盘。Redis 提供 3 种刷新策略,配置项为appendfsync:
策略值 | 含义 | 数据安全性 | 性能影响 |
---|---|---|---|
always | 每执行一条命令,立即刷新缓冲区到磁盘 | 最高(仅丢失操作系统崩溃数据) | 最低(频繁磁盘 I/O,适合金融场景) |
everysec | 每秒刷新一次缓冲区到磁盘(默认策略) | 较高(最多丢失 1 秒数据) | 中等(平衡安全与性能) |
no | 由操作系统决定何时刷新(通常 30 秒) | 最低(可能丢失几十秒数据) | 最高(适合非核心数据) |
默认是everysec

4.3 重写机制(瘦身 AOF 文件)
aof文件持续增长,体积越来越大,会影响到redis下次的启动时间。(redis启动时读取aof文件恢复内容)
但是aof中的文件,有一些是冗余的

redis存在一个机制,能剔除aof文件的冗余,达到文件 瘦身 的效果。
aof的重写机制(rewrite)和 rbd一样也分为手动触发 和 自动触发
重写的触发方式
- 手动触发:执行bgrewriteaof命令,异步重写(类似bgsave,通过 fork 子进程执行);
bash
127.0.0.1:6379> bgrewriteaof # 后台重写AOF文件
Background append only file rewriting started
- 自动触发:Redis 根据 AOF 文件大小自动触发,配置项如下:
bash
# AOF文件大小超过"基准大小"的100%(即翻倍)时触发重写
auto-aof-rewrite-percentage 100
# 基准大小:AOF文件最小重写阈值(默认64MB),低于此值不触发
auto-aof-rewrite-min-size 64mb
重写流程(与bgsave类似,但有缓冲区优化)

- 父进程判断:检查是否有bgsave或 AOF 重写进程在运行,若有则等待;
- 创建子进程:父进程fork子进程,子进程读取内存数据,生成最简 AOF 命令,写入临时文件;
- 父进程处理新命令:重写期间,父进程将新的修改命令同时写入 "原 AOF 缓冲区" 和 "重写缓冲(aof_rewrite_buf)";
- 合并缓冲区:子进程重写完成后,父进程将 "重写缓冲区" 的命令追加到临时文件;
- 替换旧文件:临时文件重命名为appendonly.aof,替换旧文件,重写完成。
重写的时候,不关心aof文件原来有什么,只需要把内存中当前的数据读取出来,以aof的格式写道另一个aof文件中。
AOF 重写时是根据内存中的最终数据结果,反向生成 "能直接得到这个结果" 的最简指令。
fork创建子进程的一瞬间--》子进程继承了fork时的内存状态--》根据内存状态反推 最简指令 ---》写入新的aof中。
父进程把fork之后的数据以aof的格式写入到aof_rewrite_buf中--》之后追加到子进程的新aof中 ---》再就可以替换旧aof文件了
追加的aof数据可能存在冗余,因为是实时根据内存反推的指令,没有剔除冗余的操作。
此处子进程写入数据类似rdb生成快照
不过rdb是以二进制的方式生成的,aof重写则是按照文本的格式生成的。
注意:
执行bgrewriteaof时,redis已经在进行aof重写了 ---》直接返回
redis在生成rdb文件的快照--》等待rdb生成完快照,再进行aof重写
rdb对于fork之后的数据,不会保存,aof对fork后的数据会通过aof_rewrite_buf缓冲区的方式追加。
因为aof是实时备份,rdb是定期备份,期限就是每次fork的那个时刻。
5.混合持久化
为解决 "RDB 加载慢" 和 "AOF 体积大" 的问题,Redis 4.0 推出 "混合持久化"------AOF 重写时,先将当前内存数据以 RDB 二进制格式写入 AOF 文件,再将重写后的新命令以 AOF 文本格式追加,形成 "RDB 头部 + AOF 尾部" 的混合文件。

配置文件里默认是开启的。
触发aof重写后,会把当前内存的状态按照 rdb的二进制格式写入新的aof中,再进行aof的写入操作。
可以看到,上面是rdb数据,下面是aof数据。
redis上同时存在aof文件和rdb快照时---》以aof为主 (aof包含的数据更全)

6.小结
Redis 的三种持久化方案各有侧重:
- RDB 是 "定期快照",适合备份和快速加载,缺点是数据安全性低;
- AOF 是 "实时日志",数据安全性高,缺点是加载慢、文件体积大;
- 混合持久化结合两者优势,是当前生产环境的最优选择。
实际使用中,需根据 "数据重要性""性能要求""备份策略" 综合选择 ------ 核心是 "不盲目追求高安全性而牺牲性能,也不忽视数据安全仅追求速度",找到适合业务的平衡点。