Redis

Redis 持久化机制

·7 分钟阅读·2438 字

RDB、AOF、AOF重写、混合持久化——原理与生产实践

📋 目录

Redis 持久化机制

涵盖 RDB 快照、AOF 日志、AOF 重写机制、混合持久化,以及生产环境下的故障恢复策略。

RDB 与 AOF 对比

一、一句话结论

RDB是全量镜像、丢数据风险大;AOF逐条记录写指令、数据完整性更高,生产故障优先AOF恢复;混合持久化是4.0后最优方案。

二、RDB短板(为什么不能用来快速恢复业务)

1. 定时快照,必然丢失两次快照之间的数据

RDB触发:手动bgsave/配置定时策略save m n
例:配置1小时生成一次RDB,宕机丢失近1小时全部写入数据,业务无法接受。

RDB是某一瞬间内存镜像,中间增量无落地。

2. bgsave全量fork子进程,生产不敢高频执行

bgsave调用fork()创建子进程,拷贝页表、占用CPU+内存

  • 大数据量fork耗时高、瞬时STW;
  • 频繁RDB拖垮Redis性能,生产只能低频落地快照。
    不能靠高频RDB来减少丢数据。

3. RDB文件损坏直接整库报废

RDB是单一二进制文件,磁盘坏块、落盘异常,整个RDB无法加载,全量数据报废。

三、AOF天然优势(生产恢复首选)

1. 落地粒度可控,最大限度少丢数据

AOF记录每一条写命令,三种刷盘策略:

  1. appendfsync always:每条写立刻落盘,宕机0丢失(性能偏低,金融场景);
  2. appendfsync everysec:每秒刷一次磁盘(生产默认,最多丢1秒数据);
  3. no:交给OS缓冲区,丢数据不可控。

最多丢1s数据,远优于RDB动辄分钟/小时级丢失。

2. 恢复逻辑:重放指令,增量+全量全覆盖

AOF=顺序日志,Redis启动逐条回放日志还原数据,哪怕中间少量损坏,可手动裁剪异常命令,剩余数据正常恢复。

3. AOF文件可人工修复

文本格式日志,误删key、误执行flushdb,可以打开AOF删掉对应指令再恢复;RDB二进制看不懂,无法手动修正。

四、关键:Redis4.0+混合持久化(AOF内部嵌套RDB)

混合AOF结构:

文件前半段=RDB二进制全量快照 + 后半段=增量AOF日志

  1. AOF重写bgrewriteaof时,先dump当前全量数据生成RDB写入AOF头部;
  2. 重写之后新写入命令继续追加AOF。

兼顾两大优点:

  1. 恢复速度≈RDB(前半段RDB快速加载全量);
  2. 数据安全≈纯AOF(后半段增量日志不丢新数据);

现在生产标准配置:开启AOF+混合持久化,不靠独立RDB文件做日常恢复。

五、RDB真实生产定位(不是恢复,做备份)

RDB不作为宕机应急恢复,用途:

  1. 冷备份、异地归档:定期手动bgsave,把RDB传到异地机房做灾备;
  2. 主从初次全量同步:主库生成RDB传给从库初始化;
  3. 混合AOF内部使用,不单独落地文件。

AOF 重写机制详解

一、为什么需要AOF重写

问题根源

AOF持续追加每条写指令,同一个key多次修改会冗余大量命令:

set num 1
set num 2
set num 3
del num

原始AOF存4条指令;实际最终num已删除,重写后这条数据直接消失
长期运行AOF文件无限膨胀:磁盘占满、重启回放AOF极慢。

AOF重写:根据当前内存真实数据生成最简指令,替换旧AOF,压缩体积。

二、重写触发两种方式

  1. 手动触发:bgrewriteaof(客户端命令)
  2. 自动触发:配置阈值
auto-aof-rewrite-percentage 100 # 当前AOF比上次重写后增大100%触发
auto-aof-rewrite-min-size 64mb # AOF最小64MB才允许自动重写

三、bgrewriteaof完整执行流程(fork子进程,无阻塞主线程)

  1. 主线程调用fork()生成子进程
    子进程拥有内存数据快照(写时复制COW),主线程继续正常处理客户端命令,不阻塞业务
  2. 子进程遍历全库数据,生成精简新AOF临时文件(aof.rewrite)
  • String:只存最终set;
  • List:批量rpush一次性写入;
  • Hash:hmset批量;
  • 过期/已删除key直接丢弃,不写入新日志;

只保留数据最终状态,删除中间冗余操作。

  1. 主线程开辟AOF重写缓冲区(aof_rewrite_buf)
    fork之后主线程新收到的新增写命令
  • 正常追加到老AOF;
  • 同时写入重写缓冲区(防止重写期间丢失增量数据)。
  1. 子进程写完临时新AOF,通知父进程
    主线程把重写缓冲区全部内容追加到新临时AOF末尾

这一步补齐fork之后新增的数据,保证新AOF数据完整。

  1. 原子替换文件:rename新文件覆盖旧AOF,重写结束。

关键:全程不阻塞Redis主线程

只有fork瞬间短暂STW(拷贝页表),大数据量fork会卡顿,是生产唯一隐患。

四、混合持久化关联(4.0+)

开启aof-use-rdb-preamble yes
重写生成的新AOF头部是RDB二进制全量数据,尾部是增量AOF指令

  1. 重启加载:先快速加载RDB全量,再回放尾部少量AOF,兼顾速度与安全;
  2. 没开混合:新AOF全是文本指令,文件偏大、启动回放慢。

五、生产三大踩坑点

  1. fork耗内存:fork瞬间复制页表,内存占用瞬时翻倍,物理内存不足触发swap、卡顿;
  2. 频繁自动重写:阈值配置过小,短时间多次fork压垮CPU;
  3. 磁盘IO打满:重写写新AOF+主线程同步刷旧AOF双写磁盘,IO飙升。

关联文档