一、Redis为什么需要持久化?

Redis的核心优势是基于内存读写,内存的超高吞吐、低延迟特性,支撑了它的高性能。但内存有一个致命短板:易失性

一旦服务器断电、进程宕机,内存中所有数据会瞬间清空,对于业务数据而言是毁灭性的损失。

为了解决高性能内存存储和数据不丢失的矛盾,Redis官方设计了两套经典持久化方案:RDB快照AOF日志,并在4.0版本推出了融合二者优势的混合持久化,覆盖绝大多数生产场景。

接下来我们带着思考逐一拆解:每种方案解决了什么问题?又牺牲了什么?适合什么场景?

二、RDB快照

2.1 什么是RDB?

RDB是Redis的全量数据快照。简单来说,它会在指定时间节点,将Redis内存中所有的完整数据,以压缩二进制的形式写入磁盘,生成后缀为.rdb的快照文件。

你可以通俗理解为:给Redis内存数据拍一张高清全景照片,存档留存。

2.2 RDB的两种生成方式

RDB快照的保存分为两种模式,核心差异在于是否阻塞主线程,这也是生产环境选型的关键:

1. save(同步保存)

主进程直接执行快照保存,全程阻塞Redis所有的读写请求,直到快照写入完成。

这种方式会直接导致服务卡顿、业务请求超时,性能极差,线上环境绝对禁用,仅适用于本地测试、单机离线备份场景。

2. bgsave(后台异步保存)

生产环境唯一推荐方案。Redis会通过fork()系统调用,创建一个独立子进程,由子进程全权负责内存数据读取、RDB文件生成与写入。

整个过程中,主线程不参与快照操作,持续正常处理用户的读写命令,完全不影响业务运行,兼顾了持久化和服务性能。

2.3 核心底层:COW写入时复制(无锁并发思想)

看到这里很多人会有疑问:子进程在读内存数据生成快照,主进程同时修改内存数据,不会出现数据错乱、并发冲突吗?

这是RDB最核心的设计亮点:基于操作系统的COW(Copy On Write,写入时复制)机制,实现无锁并发,完美规避冲突。

完整执行流程如下:

  1. 子进程fork完成后,共享主进程的内存数据,开始读取内存数据、准备生成RDB快照;

  2. 若此时主进程需要修改某一块内存数据,操作系统不会直接覆盖原数据;

  3. 操作系统先将原始内存数据复制一份生成副本

  4. 主进程修改新生成的副本内存,响应业务请求;

  5. 子进程继续读取原始内存数据,完成完整、一致的快照写入。

全程无需加锁,既保证了快照数据的一致性,又不阻塞主线程,极致贴合Redis的高性能定位。

技术类比:Java中的CopyOnWriteArrayList,核心原理和COW完全一致,都是读原数据、写新副本的无锁并发设计。

2.4 RDB的优缺点

优点

  • 文件体积小:采用二进制压缩格式存储,相比日志文件,占用磁盘空间更少,备份、传输效率更高;

  • 故障恢复速度极快:Redis重启恢复数据时,只需直接将二进制RDB文件加载到内存,无需逐条解析执行命令,大数据量场景下恢复效率碾压AOF。

缺点

  • 存在数据丢失风险:bgsave是耗时操作,无法频繁执行,只能定时触发快照保存。如果两次快照间隔期间Redis宕机,这段时间的所有新增、修改数据会全部丢失;

  • 大内存场景fork开销大:内存数据量超大时,fork子进程会消耗一定CPU资源,短暂影响服务性能。

三、AOF日志

为了解决RDB定时快照、易丢增量数据的痛点,Redis推出了AOF持久化机制,核心思路彻底反转:不存数据结果,只存操作过程

3.1 什么是AOF?

AOF是增量命令日志持久化。它会记录Redis每一条执行成功的写命令,以文本日志的形式追加到AOF文件中。

重启恢复数据时,Redis会逐条回放AOF日志中的命令,复刻所有数据操作,还原完整数据。

3.2 AOF完整写入流程

一条写命令从执行到落地磁盘,分为4个步骤:

接收写命令 → 主线程执行命令 → 写入AOF内存缓冲区 → 进入操作系统缓存页 → 最终刷入磁盘持久化

多级缓存的设计,是为了平衡IO性能和数据安全,由此衍生出三种核心刷盘策略。

3.3 三种刷盘策略

1. always(实时刷盘)

每一条写命令执行完成后,立刻强制刷盘落地。

特点:数据安全性最高,几乎不会丢失任何数据;但频繁触发磁盘IO,性能损耗极大,生产环境不推荐

2. everysec(每秒刷盘 - 默认策略)

将1秒内的所有写命令统一缓存,每秒批量刷盘一次。

特点:完美平衡性能与数据安全,正常场景最多丢失1秒内的数据,是绝大多数生产环境的首选方案

3. no(系统自主刷盘)

Redis不干预刷盘时机,完全交由操作系统自主调度缓存刷盘。

特点:Redis性能最优,但宕机时会丢失大量未刷盘数据,数据安全性极差。

3.4 为什么AOF先执行命令,再写日志?

对比MySQL的redo log先写日志、再执行事务的设计,很多人会疑惑:Redis为什么反其道而行之?

核心是两款产品的核心定位不同,设计目标完全不同

  • MySQL是关系型数据库,核心优先级:事务可靠、数据绝对安全 > 性能,所以先写日志兜底,防止事务执行失败数据错乱;

  • Redis是缓存中间件,核心优先级:高性能、低延迟 > 绝对数据安全,所以先执行命令、再写日志。

这种设计的好处是:不会阻塞当前业务请求,最大化保证吞吐性能;唯一弊端是,命令执行完成后、日志未刷盘前宕机,该条数据会永久丢失。

3.5 AOF核心优化:重写机制

AOF有一个致命缺陷:对同一个key反复增删改,会产生大量冗余无效命令。比如同一个key连续修改100次,AOF会记录100条命令,但最终仅最后一条生效。

长期运行会导致AOF文件体积持续膨胀,不仅占用大量磁盘空间,还会让重启日志回放的耗时大幅增加,严重影响恢复效率。

为解决这个问题,Redis引入AOF重写机制

Redis fork子进程,扫描当前内存中最新的真实数据,摒弃所有冗余命令,生成能还原数据的最简写命令,组成全新的、体积更小的AOF文件,最终替换旧的冗余AOF文件。

重写全程不影响主线程业务,高效压缩日志体积,是AOF机制不可或缺的优化。

四、混合持久化

梳理完RDB和AOF的优缺点,我们能清晰发现二者的互补性:

  • RDB:恢复快、体积小,但易丢数据;

  • AOF:数据安全、丢失数据少,但恢复慢、日志易冗余。

有没有一种方案,能同时保留两者的优点,规避所有短板?Redis 4.0推出的混合持久化,完美解决了这个问题,也是目前生产环境的最优持久化方案

4.1 混合持久化核心原理

混合持久化基于AOF重写机制实现,核心是「前半段RDB全量快照 + 后半段AOF增量日志」的组合格式:

  1. 触发AOF重写时,子进程先将当前内存的全量数据,以RDB二进制格式写入新AOF文件的前半段;

  2. 重写过程中,主线程新产生的增量写命令,以AOF日志格式追加到文件后半段;

  3. 最终生成一份「RDB头+AOF尾」的混合格式持久化文件。

4.2 数据恢复逻辑

Redis重启恢复数据时,分段加载、兼顾速度与完整性:

  1. 优先加载文件前半段的RDB二进制快照,快速还原大部分数据,保障恢复速度;

  2. 再逐条执行后半段的AOF增量日志,补齐重写期间的新增数据,保证数据零丢失。

以RDB保障恢复速度,以AOF保障数据安全,彻底解决了纯RDB丢数据、纯AOF恢复慢的两大痛点,是生产环境的首选方案

Redis的三套持久化方案,没有绝对的优劣,只有场景适配。所有技术设计的本质,都是在性能、安全、资源三者中做权衡:

想要极致性能,就要容忍少量数据丢失;想要绝对数据安全,就要牺牲部分性能;想要两全其美,就需要更复杂的混合设计。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐