Redis 持久化:RDB、AOF 与混合模式
橙风小兔
5 分钟阅读
判断先说:Redis 把数据放在内存里换来速度,持久化解决的是"进程挂了、机器重启后数据还在不在"的问题。RDB 和 AOF 是两套机制,一个快但可能丢一段时间,一个细但文件大、恢复慢,混合模式把两者优点拼到一起。选哪个取决于你能接受丢多少数据,而不是哪个听起来更先进。
RDB:某个时刻的内存快照
RDB 把当前内存里的数据以二进制压缩格式整体写一份快照到磁盘。触发方式有两种:手动 SAVE(阻塞主线程,生产禁用)和 BGSAVE(fork 子进程后台写,不阻塞服务)。BGSAVE 时主进程 fork 出一个子进程,子进程遍历内存把数据序列化到磁盘,主进程继续响应请求。
save 900 1 # 900 秒内至少 1 次修改,触发 BGSAVE
save 300 100 # 300 秒内至少 100 次修改
save 60 10000
RDB 的优点是文件紧凑、恢复极快,适合做冷备和主从全量同步的基准。缺点也明显:两次快照之间发生崩溃,那段时间的所有写入就丢了;BGSAVE 的 fork 在数据量大、内存页多时会有停顿,且 fork 瞬间若开启写时复制,内存会瞬时占用升高。所以"快照间隔"本质是在"恢复速度/磁盘占用"和"数据丢失窗口"之间做权衡。
AOF:把写命令追记下来
AOF(Append Only File)记录的是"执行的写命令",以追加方式写入日志文件,重启时重放这些命令来重建数据。它记录粒度是"每条写操作",所以理论上丢失的数据比 RDB 少得多。
appendonly yes
appendfsync everysec # 每秒刷盘一次,崩溃最多丢 1 秒
appendfsync 有三个档位:always 每条命令都刷盘,最安全但最慢,每次写都要等磁盘;everysec 每秒刷一次,是默认且较均衡的选择,最多丢一秒;no 交给操作系统调度,性能最好但丢失窗口不确定。即便选 everysec,也只在"写命令已进操作系统缓冲但未落盘"那一秒的极小窗口可能丢数据,比 RDB 的分钟级窗口安全得多。
AOF 文件会随写入不断膨胀,因为一条 key 被改一百次,日志里就有一百条。Redis 用 BGREWRITEAOF 在后台把文件重写压缩成"能重建当前数据集的最小命令集",类似对日志做瘦身。重写过程同样 fork 子进程,不影响主线程。
混合模式:RDB 做底、AOF 做增量
单纯 AOF 重启重放慢——要一条条重放可能很长的日志;单纯 RDB 丢数据多——两次快照间全丢。Redis 4.0 起的混合持久化把两者结合:AOF 重写时,先把当前内存数据以 RDB 格式写入文件头部,再把之后的增量写命令以 AOF 格式追加。
aof-use-rdb-preamble yes # 开启 AOF 文件以 RDB 开头
这样恢复时,先按 RDB 快速载入主体数据,再重放后面一小段 AOF 增量,兼顾速度与数据安全。线上经验上,这是多数需要持久化的场景的首选配置:既保留了 AOF 秒级丢失的保护,又享受了 RDB 的快速恢复。它本质上是"用 RDB 扛主体、用 AOF 补尾部"的折中。
几个边界条件
- 主从架构下,从节点崩溃重启通常触发全量同步而非依赖自身持久化;持久化策略仍按主节点承受的丢失窗口来定。从节点一般不单独承担持久化职责。
- 开了持久化不等于不会丢数据。机器断电且
appendfsync 非 always 时,未刷盘部分必然丢失,这是磁盘语义决定的,任何数据库都无法违背。
- 超大内存实例做
BGSAVE/BGREWRITEAOF 的 fork 代价高,要预留内存余量并监控 fork 耗时,避免在高峰期触发。一个常见事故是实例内存几十 GB,fork 时延迟陡增,把业务请求拖超时。
- 把 Redis 当纯缓存、允许丢失的场合,完全可以关闭持久化以换取最高吞吐,但要在架构上保证"缓存 miss 能回源",而不是假设数据永远在。否则重启后缓存全空、流量直冲数据库,可能直接打挂后端。
- 持久化文件要备份到独立介质。RDB/AOF 文件本身也会损坏,定期把快照拷到异地,是容灾的基本动作,不能只依赖本地磁盘。
持久化与复制的关系
持久化和主从复制是两件事,但常被混为一谈。复制解决的是"数据多副本、高可用",持久化解决的是"单机重启后不丢"。从节点默认不靠自己的持久化恢复,而是靠从主节点全量同步。所以即使开了 RDB,从节点崩溃后大概率仍是全量重同步,而非读本地快照。真正影响数据安全的是主节点的持久化配置加上合理的副本数。不要把"有从库"当成"不用做持久化"的理由,主库磁盘损坏且持久化间隔太长,从库同步的也是已丢失的数据。两者职责不同,都得各自做好。
浏览 0
点赞 0
评论 0