2. Redis持久化与数据安全
Redis 是内存数据库,数据默认只存在于内存中。一旦进程崩溃、宿主机断电或容器被强制销毁,内存中的数据就会全部丢失。持久化机制的作用,就是把内存中的数据以某种形式落到磁盘上,使得 Redis 重启后能够重新加载数据。理解 RDB 与 AOF 的差异,不只是为了“数据不丢”,更关键的是:它直接决定了主从切换时能恢复多少数据、切换需要多长时间。这两点正是高可用集群设计中必须量化的核心指标。
RDB:某一时刻的全量快照
RDB(Redis Database)保存的是某一时刻内存数据的二进制快照。触发方式主要有两类:一是手动执行 SAVE 或 BGSAVE,二是通过配置自动触发。生产环境几乎只用 BGSAVE,因为它会 fork 出一个子进程完成写盘,主进程继续处理命令。
fork 之后,子进程与父进程共享同一份物理内存页,依靠操作系统的写时复制(Copy-On-Write,COW)机制:父进程修改某个内存页时,内核才复制该页给子进程。因此 RDB 生成期间,如果写入非常频繁,内存占用会显著上升,极端情况下可能达到原数据量的两倍。这是 RDB 在高写入场景下最需要警惕的副作用。
自动触发的典型配置如下:
save 900 1 # 900 秒内至少 1 次修改则触发
save 300 10 # 300 秒内至少 10 次修改则触发
save 60 10000 # 60 秒内至少 10000 次修改则触发
dbfilename dump.rdb
dir /data/redis
rdbcompression yes
rdbchecksum yes
stop-writes-on-bgsave-error yes
其中 stop-writes-on-bgsave-error yes 值得特别说明:当最近一次 BGSAVE 失败(例如磁盘满、权限错误)时,Redis 会拒绝所有写命令。这看似“过于严格”,但它避免了“以为在持久化、实际早已失败”的假安全状态。在集群中,如果主节点因此停止写入,从节点也会同步不到新数据,需要监控及时告警。
RDB 的优点是文件紧凑、加载速度快,非常适合做备份和全量恢复;缺点是两次快照之间的数据会丢失。假设配置为 save 300 10,最坏情况下可能丢失接近 5 分钟的数据。
AOF:追加式的命令日志
AOF(Append Only File)记录的是每一条写命令,以 Redis 协议格式追加到文件末尾。重启时,Redis 重新执行这些命令来重建数据集。AOF 的核心配置是刷盘策略:
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
appendfsync 有三个取值,直接决定数据丢失窗口:
- always:每条写命令都 fsync 到磁盘。数据几乎不丢,但吞吐量大幅下降,通常只有 everysec 的几分之一。
- everysec:每秒 fsync 一次,是默认值。最坏丢失约 1 秒的数据,性能与安全的平衡点。
- no:由操作系统决定何时刷盘,通常约 30 秒一次,丢失窗口最大,性能最好。
AOF 文件会随写入不断增长,因此需要重写(rewrite)。重写同样通过 fork 子进程完成:子进程根据当前内存数据生成一份“最小命令集”的新 AOF,父进程在重写期间的新命令会同时写入旧 AOF 缓冲区和重写缓冲区,重写完成后合并。触发条件是文件体积比上次重写后增长超过 auto-aof-rewrite-percentage,且不小于 auto-aof-rewrite-min-size。
混合持久化与恢复流程
Redis 4.0 之后支持混合持久化(aof-use-rdb-preamble yes):AOF 重写时,文件前半部分写成 RDB 格式的全量快照,后半部分追加增量命令。这样既保留了 RDB 的加载速度,又保留了 AOF 的低丢失窗口,是目前推荐的生产配置。
恢复流程遵循“AOF 优先”原则:如果开启了 AOF 且 AOF 文件存在,Redis 启动时只加载 AOF,忽略 RDB;否则加载 RDB。加载 AOF 时,先读 RDB 前导部分,再逐条执行后续命令。如果 AOF 文件末尾因宕机而截断,可用 redis-check-aof --fix 修复,它会丢弃不完整的尾部命令。
dir 与 dbfilename/appendfilename 指向的文件确实存在且权限正确。很多“数据没恢复”的故障,其实是启动目录不对,加载了空文件。持久化如何影响故障切换
在哨兵或 Cluster 架构中,主节点故障后由从节点晋升。此时有两个关键量:切换时间和数据丢失窗口。
切换时间由“故障检测 + 选举 + 从节点晋升 + 客户端重定向”构成。持久化对它的影响主要体现在从节点晋升阶段:如果从节点开启了 AOF 且 appendfsync always,晋升时需要完成一次 AOF 重写或大量 fsync,会拖慢切换;而 RDB 加载虽然快,但如果从节点刚重启、需要先加载大 RDB 文件,也会延长不可用时间。
数据丢失窗口则由复制和持久化共同决定。主节点故障瞬间,尚未同步到从节点的写入会丢失;即使从节点有 AOF,也只能保住“已经收到并落盘”的部分。因此实际丢失窗口 ≈ 复制延迟 + 从节点刷盘间隔。若从节点用 everysec,最坏再叠加约 1 秒。
下面这张图把 RDB 与 AOF 在“写入 → 落盘 → 恢复 → 切换”链路上的差异并列呈现,便于对照选择。
生产配置建议与判断依据
综合来看,推荐的生产组合是:开启 AOF + everysec + 混合持久化,同时保留 RDB 用于定期备份。这样正常运行时丢失窗口约 1 秒,重启加载又借助 RDB 前导保持较快速度。若业务对丢失极度敏感(如金融扣款),可对关键实例使用 appendfsync always,但必须接受吞吐下降,并通过压测确认是否满足容量要求。
判断配置是否合理,可以问三个问题:第一,最坏情况下能接受丢多少秒数据?这决定 appendfsync。第二,从节点晋升需要多久?这取决于 AOF 文件大小和重写频率,建议把 auto-aof-rewrite-min-size 控制在合理范围,避免文件过大导致恢复缓慢。第三,磁盘是否可靠?stop-writes-on-bgsave-error 和磁盘监控必须开启,否则持久化失败会静默演变成数据安全事故。
最后需要强调:持久化解决的是“单机重启不丢数据”,而高可用解决的是“节点故障仍可服务”。两者必须配合。持久化配置决定了故障切换后能恢复到的数据点,也间接影响切换耗时。在设计集群时,应把 appendfsync、重写阈值、RDB 触发规则与哨兵/Cluster 的故障检测参数放在一起评估,而不是孤立地调优某一项。