Redis 持久化策略
在实际用 Redis 的时候,会遇到一个核心问题:服务器重启后,之前存在内存里的数据怎么保住?这时候 “持久化” 就成了关键 —— 本质上是把 Redis 内存里的数据集,以某种形式存到磁盘上,等下次启动时再读回来。
- Redis 里最核心的两种持久化方案就是 RDB 和 AOF
一、RDB:
Redis 的 “快照相机”,默认的高效备份方案
先想场景:手机里存了很多照片,每天晚上 12 点,手机会自动把所有照片打包成一个压缩包存在云端 ——RDB 做的事差不多就是这个意思。它是 Redis 默认开启的持久化方式,核心是 “在某个时间点,把内存里所有数据拍个快照,存成二进制文件(默认叫 dump.rdb)”,等重启时直接把这个 “压缩包” 读进内存,数据就回来了。
1. RDB 怎么工作?
RDB 的触发分 “自动” 和 “手动” 两种
(1)手动触发:SAVE 和 BGSAVE
手动触发靠两条命令,但差别极大,生产环境用错了可能直接导致服务卡壳:
- SAVE 命令:相当于 “让 Redis 停下所有活,专心打包快照”。执行这条命令时,Redis 主进程会被完全阻塞 —— 期间客户端发的所有请求(查数据、写数据)都得等着,直到快照生成完。如果数据量大(比如几个 G),可能堵几分钟,所以生产环境绝对不能用,顶多在测试环境小数据量时临时用用。
- BGSAVE 命令:这是生产环境的 “正确姿势”。它会让 Redis 先创建一个 “子进程”,然后主进程继续处理客户端请求,子进程专门负责把内存数据写成快照文件。等子进程做完了,会告诉主进程 “搞定了”,整个过程主进程几乎不受影响。唯一要注意的是:创建子进程时,操作系统会用 “Copy-on-Write(写时复制)” 机制复制主进程的内存页 —— 如果这时候刚好有大量写操作,可能会临时占用一些额外内存,但总体对性能影响很小。
(2)自动触发:配置文件里的 “时间 + 修改次数” 规则
实际用的时候,很少手动敲 BGSAVE,更多是让 Redis 自己判断 “什么时候该拍快照”—— 这就需要在 redis.conf 里配置触发规则,核心逻辑是 “在 N 秒内,如果数据被修改了 M 次,就自动执行 BGSAVE”。
举个最常见的默认配置例子:
# 规则1:900秒(15分钟)内,至少有1个键被修改 → 触发BGSAVE
save 900 1
# 规则2:300秒(5分钟)内,至少有10个键被修改 → 触发BGSAVE
save 300 10
# 规则3:60秒(1分钟)内,至少有10000个键被修改 → 触发BGSAVE
save 60 10000
这里的逻辑很灵活:比如 Redis 做缓存用,数据更新不频繁,可能 15 分钟才改 1 次,那触发规则 1 就够;如果是高频写入场景(比如秒杀计数),1 分钟改 1 万次,就会触发规则 3,避免快照间隔太长导致数据丢失太多。
- 另外要注意:如果想临时关闭自动 RDB,不用改配置文件,直接执行
config set save ""
就行,重启后会恢复配置。
2. RDB 的优缺点:
(1)优点:速度快、体积小,备份、恢复方便
- 文件体积小,传输成本低:因为是二进制压缩文件,同样的数据量,RDB 文件比后面要讲的 AOF 小很多。比如 1G 内存的数据,RDB 可能只有 200M,这就很适合做 “异地备份”—— 比如每天凌晨把 dump.rdb 传到其他服务器,就算本地磁盘坏了,也能从异地恢复。
- 恢复速度秒杀 AOF:重启 Redis 时,加载 RDB 文件就是 “把二进制数据直接读进内存”,不用做任何计算;而 AOF 需要重新执行所有写命令,数据量大的时候,RDB 恢复可能只要几秒,AOF 要几分钟甚至更久。
- 对主进程性能影响小:只要用 BGSAVE,主进程不受影响,子进程负责打包,除非数据量极大导致写时复制开销高,否则几乎感觉不到性能波动。
(2)缺点:数据安全性存在问题,且大文件可能卡性能
- 数据丢失风险高:这是 RDB 最大的问题。比如你配置的是 “60 秒内改 1 万次触发快照”,如果刚过了 50 秒,Redis 突然宕机了 —— 这 50 秒内的所有修改都会丢,因为快照还没生成。如果你的业务不能接受 “丢几分钟数据”(比如支付系统),那单靠 RDB 肯定不行。
- 大数据量时可能有性能波动:虽然 BGSAVE 用子进程,但如果内存里有几十 G 数据,创建子进程时的 “写时复制” 可能会让 Redis 临时卡顿一下(比如几百毫秒到几秒),尤其在峰值流量时,这个卡顿可能会影响用户体验。
- 快照生成时占用额外磁盘 IO:子进程写快照文件时,会占用磁盘 IO,如果服务器上还有其他高 IO 服务(比如 MySQL),可能会互相抢资源,导致整体性能下降。
二、AOF:Redis 的 “操作日志”,追求数据安全的首选
如果说 RDB 是 “拍快照”,那 AOF 就是 “写日记”—— 它不存数据本身,而是把 Redis 执行过的所有 “写命令”(比如 SET、HSET、INCR 这些会改数据的命令)都记下来,存到一个文本文件(默认叫 appendonly.aof)里。等 Redis 重启时,就把这个 “日记” 从头到尾读一遍,重新执行所有命令,这样数据就恢复到宕机前的状态了。
比如执行三条命令:
SET name "zhangsan"
INCR age 1
HSET user id 1001
那 AOF 文件里就会记录这三条命令(当然格式会有点不一样,比如带时间戳和校验信息),重启时再执行一遍,数据就回来了。
1. AOF 的核心:同步策略决定 “安全与性能的平衡”
AOF 的关键问题是:“写命令什么时候从内存写到磁盘?”—— 如果命令只存在内存,宕机还是会丢,所以必须同步到磁盘才安全。但磁盘 IO 比内存慢得多,同步太频繁会影响性能,同步太懒又会丢数据。Redis 提供三种同步策略,在 redis.conf 的appendfsync
配置项里:
(1)appendfsync always:最安全,但性能最差
配置成这个值后,每执行一条写命令,Redis 都会立即把命令写到磁盘上的 AOF 文件里。这意味着只要命令执行成功,数据就一定在磁盘上,就算 Redis 马上宕机,也不会丢任何数据 —— 安全性拉满。
但问题也很明显:每一条写命令都要触发一次磁盘 IO,而磁盘 IO 的速度比内存慢好几个数量级。如果 Redis 每秒要处理几万次写请求,那每次都等磁盘写完,Redis 的吞吐量会直接掉下来,甚至可能卡得没法用。所以这种策略只适合 “对数据零丢失有极致要求” 的场景(比如金融交易系统),大部分业务用不上。
(2)appendfsync everysec:默认配置,平衡安全与性能
这是 Redis 默认的配置,意思是 “每秒同步一次”——Redis 会把这一秒内所有的写命令先存到 “AOF 缓冲区”(内存里),每过一秒,就把缓冲区里的所有命令一次性写到磁盘上。
这种策略下,就算宕机,最多只会丢 “最后一秒内” 的命令,这个数据丢失量对大部分业务(比如电商商品库存、用户会话)来说是可接受的。同时,每秒一次的批量 IO,对性能的影响也比较小,算是 “性价比最高” 的选择,大部分生产环境用这个就够了。
(3)appendfsync no:性能最好,但最不安全
这个配置的意思是:“Redis 不管同步的事,全交给操作系统”——Redis 只把写命令写到 AOF 缓冲区,然后就不管了,操作系统会自己决定什么时候把缓冲区的数据刷到磁盘(比如操作系统内存不够了,或者过了 30 秒)。
这种策略下,Redis 的性能最好,因为不用等磁盘 IO,但数据丢失风险也最高 —— 如果操作系统宕机,可能会丢几分钟甚至更久的数据。所以这种策略只适合 “数据丢了也无所谓” 的场景(比如纯缓存,数据丢了能从数据库重新加载),一般不推荐在核心业务用。
2. AOF 的痛点:文件膨胀与重写机制
用 AOF 久了,会发现一个问题:AOF 文件越来越大。若类似反复修改同一个键,AOF 会把每一次修改的命令都记下来,导致大量冗余。
-
举例子:
执行了 1000 次
INCR count 1
,最后 count 的值是 1000。但 AOF 文件里会记 1000 条 INCR 命令,而实际上,恢复数据只需要一条SET count 1000
就够了 —— 这 1000 条命令里,有 999 条都是多余的,会让 AOF 文件变得非常大,不仅占磁盘空间,重启时恢复数据也会变慢(要执行 1000 条命令)。
为解决这个问题,Redis 引入了 “AOF 重写” 机制 —— 简单说就是 “把 AOF 里的冗余命令删掉,只保留恢复当前数据必需的最小命令集”。
(1)AOF 重写怎么工作?
重写的过程和 BGSAVE 类似,也是 “主进程干活,子进程重写”:
- Redis 会创建一个子进程,子进程先读取当前内存里的所有数据;
- 然后针对每一个键,生成一条 “能直接恢复该键数据” 的命令(比如用 SET 代替多次 INCR,用 HMSET 代替多次 HSET);
- 子进程把这些命令写到一个 “临时 AOF 文件” 里;
- 在子进程重写期间,Redis 会把新收到的写命令同时写到 “旧 AOF 文件” 和 “重写缓冲区” 里(保证不丢新命令);
- 等子进程重写完,Redis 会把 “重写缓冲区” 里的新命令追加到临时 AOF 文件里,然后用临时文件替换旧 AOF 文件 —— 重写完成。
整个过程主进程不会阻塞,也不会丢数据,安全。
(2)怎么触发重写?手动 + 自动
-
手动触发:执行
BGREWRITEAOF
命令,和 BGSAVE 一样,不会阻塞主进程,生产环境可以放心用。 -
自动触发:在 redis.conf 里配置两个参数,让 Redis 自己判断什么时候重写:
# AOF文件体积比上次重写后的体积大多少百分比时触发重写,默认100(即翻倍) auto-aof-rewrite-percentage 100 # AOF文件体积至少达到多少字节才触发重写,默认64MB(避免小文件频繁重写) auto-aof-rewrite-min-size 64mb
比如上次重写后 AOF 文件是 64MB,那下次当文件涨到 128MB(64*2)时,Redis 就会自动触发 BGREWRITEAOF,把文件压缩回几十 MB。
(3)AOF 文件损坏了怎么办?
AOF 是文本文件,偶尔可能因为磁盘错误或宕机导致文件损坏(比如最后几行命令没写完),这时候 Redis 重启会报错,没法加载 AOF 文件。Redis 自带了修复工具redis-check-aof
:
- 先把损坏的 AOF 文件备份一份(防止修复失败);
- 执行
redis-check-aof --fix appendonly.aof
,工具会自动删除损坏的部分,保留完好的命令; - 重启 Redis,就能正常加载修复后的 AOF 文件了。
3. AOF 的优缺点:安全但有 “体积和速度” 问题
(1)优点:数据安全、文件可读,能救误操作
- 数据安全性高:默认每秒同步一次,最多丢 1 秒数据;配置成 always 能做到零丢失,对核心业务(比如支付)来说非常重要。
- 文件可读性强:AOF 是文本文件,可以直接打开看里面的命令,甚至能手动修改 —— 比如不小心执行了
FLUSHDB
(清空所有数据),只要 AOF 文件还没同步,赶紧关掉 Redis,编辑 AOF 文件删掉FLUSHDB
那一行,再重启,数据就回来了 - 数据恢复更完整:相比 RDB 可能丢几分钟数据,AOF 最多丢 1 秒,恢复的数据更接近宕机前的状态。
(2)缺点:体积大、恢复慢,性能开销比 RDB 高
- 文件体积大:同样的数据量,AOF 文件比 RDB 大很多。比如 1G 内存的数据,AOF 可能有 2-3G,甚至更大,会占用更多磁盘空间,备份和传输也更费时间。
- 恢复速度慢:重启时,AOF 需要把所有命令重新执行一遍,数据量大的时候(比如几十 G),恢复可能要十几分钟甚至更久,而 RDB 可能只要几十秒。
- 写性能开销比 RDB 高:虽然 everysec 策略已经优化了 IO,但每秒一次的批量同步还是会比 RDB 的 “偶尔拍快照” 占用更多 CPU 和磁盘 IO,在超高写入场景(比如每秒几十万次写),可能会比 RDB 的性能低 10%-20%。
三、RDB vs AOF:
1. 核心维度对比:
对比维度 | RDB | AOF |
---|---|---|
数据安全性 | 低(可能丢几分钟数据) | 高(最多丢 1 秒或零丢失) |
文件体积 | 小(二进制压缩) | 大(文本命令,冗余多) |
恢复速度 | 快(直接读二进制到内存) | 慢(重新执行所有命令) |
写性能影响 | 小(BGSAVE 子进程,偶尔波动) | 中(everysec 每秒同步,IO 开销) |
适用场景 | 性能优先、能接受丢少量数据 | 安全优先、不能接受丢多数据 |
备份便捷性 | 方便(小文件易传输) | 麻烦(大文件费空间) |
误操作恢复 | 难(快照无法编辑) | 易(文本文件可删错误命令) |
2. 混合持久化
(1)混合持久化怎么工作?
混合持久化的核心逻辑是:AOF 重写时,不再只写命令,而是先把当前内存数据以 RDB 格式写到 AOF 文件开头,然后再把重写后的命令追加到后面。
比如 AOF 文件的结构会变成这样:
[RDB二进制数据段] # 开头是RDB格式,存当前所有数据的快照
[AOF命令段] # 后面是重写后的写命令,存RDB之后的新修改
等 Redis 重启时,会先加载开头的 RDB 段 —— 快速恢复大部分数据(和纯 RDB 一样快),然后再执行后面的 AOF 命令段 —— 补充恢复 RDB 之后的新数据(和纯 AOF 一样安全),这样就兼顾了 “恢复速度” 和 “数据安全”。
(2)怎么开启混合持久化?
在 redis.conf 里配置aof-use-rdb-preamble yes
就行(Redis 5.0 + 默认就是 yes,不用改)。开启后,每次执行 BGREWRITEAOF,生成的 AOF 文件就会是 “RDB+AOF” 的混合格式。
(3)不同场景的具体选择
-
场景 1:核心业务(支付、订单、用户数据):必须开混合持久化,同时确保 AOF 同步策略是 everysec(最多丢 1 秒数据),再配合定时备份 RDB 文件(比如每天凌晨用 BGSAVE 生成快照,传到异地)—— 这样就算 AOF 文件损坏,也能从 RDB 备份恢复。
-
场景 2:缓存业务(比如商品列表缓存、热点数据缓存)
如果 Redis 只用来做缓存,数据丢了可以从后端数据库(比如 MySQL)重新加载,那对数据安全性要求没那么高,这时候有两种选择:
- 单开 RDB:如果能接受 “重启后重新加载数据库数据” 的耗时,单开 RDB 就够了 —— 配置 “15 分钟改 1 次” 或 “5 分钟改 10 次” 的触发规则,既能避免频繁快照影响性能,又能在 Redis 意外宕机时,减少从数据库重新加载的数据量(比如 15 分钟内的新缓存可以直接从 RDB 恢复,不用查数据库)。
- 关闭持久化:如果缓存数据完全可以从数据库快速加载(比如加载一次只要几秒),甚至可以直接关闭 RDB 和 AOF—— 这样 Redis 不用花资源做持久化,性能能拉到最高。但要注意:一旦 Redis 宕机,所有缓存数据都会丢失,数据库会面临短期的 “缓存穿透” 压力,需要提前做好数据库的限流和兜底
-
场景 3:数据备份与灾难恢复
不管是核心业务还是缓存业务,“异地备份” 都是必须考虑的 —— 如果服务器磁盘损坏,本地的 RDB/AOF 文件也没了,这时候异地备份就能救命。这时候 RDB 的优势就很明显了:
- 每天凌晨 3 点,用
BGSAVE
手动生成一份最新的 RDB 快照(避开业务高峰期); - 用脚本把
dump.rdb
文件通过 SCP 或 FTP 传到异地服务器(比如阿里云 OSS、腾讯云 COS,或者公司的备用服务器); - 定期(比如每周)做一次 “恢复测试”:在备用服务器上启动 Redis,加载异地备份的 RDB 文件,确认数据能正常恢复 —— 避免备份文件损坏了还不知道。
如果用 AOF 做灾难恢复,因为文件太大,传输起来耗时更长,所以一般会搭配 RDB 一起用:RDB 做异地备份(小文件快),AOF 做本地持久化(高安全)。
- 每天凌晨 3 点,用
四、RDB 与 AOF 共用:
在生产环境里,更常见的是 “两者结合”—— 用 AOF 保证日常的数据安全(最多丢 1 秒),用 RDB 做定期备份和灾难恢复(小文件易传输),再加上混合持久化兼顾恢复速度,这才是最稳妥的方案。
1. 经典组合配置
# 1. 开启RDB(默认开启,保留默认触发规则,避免频繁快照)
save 900 1
save 300 10
save 60 10000
# 避免RDB快照失败时Redis停止写操作(默认no,改成yes更安全)
stop-writes-on-bgsave-error yes
# RDB文件压缩(默认yes,节省磁盘空间,轻微消耗CPU)
rdbcompression yes# 2. 开启AOF(默认no,改成yes)
appendonly yes
# AOF文件名称
appendfilename "appendonly.aof"
# AOF同步策略(默认everysec,平衡安全与性能)
appendfsync everysec
# 避免AOF同步阻塞主进程(默认no,改成yes:同步时如果超过2秒,就暂时放弃,避免卡主进程)
no-appendfsync-on-rewrite yes# 3. 开启AOF重写(默认开启,保留默认配置)
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb# 4. 开启混合持久化(Redis 5.0+默认yes,确保配置正确)
aof-use-rdb-preamble yes# 5. 持久化文件存储路径(建议单独挂载磁盘,避免和系统盘、数据库盘抢IO)
dir /data/redis/persistence/
2. 关键运维注意事项
(1)监控持久化文件状态
- 监控文件大小:用脚本定期检查
dump.rdb
和appendonly.aof
的大小,如果 AOF 文件突然暴涨(比如几分钟内从 1G 涨到 10G),可能是程序 bug 导致大量重复写命令,要及时排查; - 监控文件修改时间:如果 RDB 文件长时间没更新(比如超过 24 小时),可能是
BGSAVE
执行失败了(比如磁盘满了、内存不够),要查看 Redis 日志(默认在dir
配置的路径下)找原因; - 监控 AOF 重写状态:用
INFO persistence
命令查看 AOF 重写的进度,如果重写长时间卡住(比如超过 1 小时),可能是磁盘 IO 太慢,要检查服务器磁盘是否有问题。
(2)避免持久化与业务高峰期冲突
- RDB 快照和 AOF 重写都会消耗 CPU 和磁盘 IO,所以要避开业务高峰期(比如电商的秒杀、直播的峰值)。可以用脚本在凌晨 2-4 点(业务低峰期)手动执行
BGSAVE
和BGREWRITEAOF
,同时把自动触发规则的阈值调大(比如把save 60 10000
改成save 60 50000
),避免高峰期自动触发。
(3)处理磁盘满的问题
- 如果持久化目录所在的磁盘满了,Redis 会停止所有写操作(不管是 RDB 还是 AOF),这时候要紧急处理:
- 先删除持久化目录下的旧备份文件(比如上周的 RDB 快照),腾出空间;
- 用
config set stop-writes-on-bgsave-error no
临时允许 Redis 继续写操作(仅应急用,之后要改回 yes); - 扩容磁盘(比如给服务器加硬盘,或者迁移到更大的云磁盘),避免再次出现磁盘满的问题。
(4)升级 Redis 时注意持久化文件兼容性
- 不同版本的 Redis 对 RDB/AOF 文件的格式可能有兼容性问题(比如 Redis 6.0 生成的 RDB 文件,可能没法在 Redis 5.0 上加载)。所以升级前要:
- 在旧版本 Redis 上执行
BGSAVE
生成最新的 RDB 文件; - 停止旧版本 Redis,备份 RDB 和 AOF 文件;
- 启动新版本 Redis,先尝试加载 RDB 文件(如果加载失败,再用
redis-check-rdb
修复); - 确认数据加载正常后,再开启 AOF(避免新版本 AOF 格式和旧版本冲突)。
- 在旧版本 Redis 上执行
五、总结:
最后梳理,彻底理清 Redis 持久化的选择逻辑:
- 优先用混合持久化:只要你的 Redis 版本是 4.0 以上,不管是核心业务还是一般业务,混合持久化都是最优解 —— 它既有 RDB 的快恢复,又有 AOF 的高安全,配置简单,运维成本低。
- RDB 用来做备份:就算开了混合持久化,也要定期(比如每天)生成 RDB 快照,传到异地做备份 —— 这是灾难恢复的最后一道防线,避免 AOF 文件损坏后无数据可恢复。
- AOF 用来保日常:用
appendfsync everysec
保证日常数据最多丢 1 秒,同时开启 AOF 重写避免文件膨胀,监控 AOF 文件状态确保正常。 - 根据业务调细节:缓存业务可以简化配置(比如关闭 AOF,只开 RDB),核心业务要加严配置(比如开启 AOF 的
always
策略,加异地备份),运维时避开高峰期,监控关键指标。
其实 Redis 持久化不难,关键是理解 “RDB 是快照、AOF 是日志” 的核心差异,再结合自己的业务需求(能不能接受丢数据、恢复要多快、性能要求多高)做配置,最后通过运维监控确保持久化正常运行