Redis持久化机制详解
什么是持久化Redis是一个内存数据库所有数据存储在内存中。一旦Redis重启需要从磁盘加载回原来的数据这就是持久化的意义。两种持久化机制RDB和AOF。一、核心知识fork与写时复制COW在了解持久化机制之前需要先理解fork和写时复制。fork的作用RDB和AOF在持久化时都会fork子进程来完成由子进程负责写入磁盘父进程继续提供服务避免阻塞。写时复制原理fork前 ┌─────────────────────────────────┐ │ 物理内存 │ │ [ 共享物理页read-only ]│ └─────────────────────────────────┘ ▲ ▲ 父进程页表 子进程页表 (指向同一块) (指向同一块)父进程触发写操作时COW发生 ┌─────────────────────────────────────────┐ │ 物理内存 │ │ [ 原物理页 ] ←── 父进程页表不变 │ │ [ 新物理页 ] ←── 子进程页表新 │ └─────────────────────────────────────────┘ 复制发生父子进程页表指向不同地址关键点fork瞬间子进程页表指向父进程相同物理页read-only父进程发生写操作时触发缺页中断才复制物理页父进程保留原物理地址子进程获得新副本目的是避免fork时复制物理内存导致父进程长时间阻塞二、AOF持久化Append Only File原理将Redis的写操作命令追加到AOF文件末尾重启时通过重放命令恢复数据。┌──────────┐ 写命令 ┌──────────┐ 追加 ┌──────────┐ │ Redis父进程 │ ────── │ 内核缓冲区 │ ────── │ AOF文件 │ └──────────┘ └──────────┘ └──────────┘ │ 重放命令恢复数据AOF写文件流程1. 客户端发送写命令 2. Redis执行命令 3. 将命令追加到AOF文件write系统调用写入内核缓冲区 4. 定期调用fsync刷盘将内核缓冲区数据写入磁盘注意write只写入内核缓冲区不保证数据落盘。AOF三种刷盘策略策略fsync调用时机可靠性性能always每个命令执行后立即fsync最高低every-sec每秒fsync一次在后台线程中等中等默认no只调用writeOS决定刷盘时机低依赖OS高always策略每个命令 → exec → fsync → 落盘优点数据最可靠每个操作都刷盘缺点性能差每个操作都要等磁盘IO完成every-sec策略推荐/默认后台线程每秒执行一次 fsync优点性能适中最多丢失1秒数据缺点宕机可能丢失约1秒内的操作no策略write → 交给OS刷盘通常等缓冲区满了才刷优点性能最高缺点容易丢失数据依赖操作系统决定刷盘时机三、AOF重写Rewrite为什么需要重写AOF只追加不清理同一个key的大量修改操作会积累冗余数据原始AOF文件 SET name tom SET name jack SET name lily SET name lucy ← 冗余数据前面三次都没用了 INCR counter INCR counter INCR counter INCR counter ← 实际只需要最终值AOF文件过大 → 数据恢复过慢重写原理AOF重写通过fork子进程根据当前内存数据生成一个精简的AOF文件。┌─────────────────────────────────────────┐ │ Redis父进程 │ │ 内存数据{name:lucy, counter:4} │ └─────────────────────────────────────────┘ │ fork ▼ ┌─────────────────────────────────────────┐ │ AOF重写子进程 │ │ 根据内存直接生成SET name lucy │ │ SET counter 4 │ │ 生成精简的AOF文件无冗余 │ └─────────────────────────────────────────┘重写缓冲区解决数据丢失在AOF重写期间父进程的写操作会记录到重写缓冲区重写期间 1. 父进程 fork 子进程基于此刻内存快照 2. 父进程继续处理写请求累积到重写缓冲区 3. 子进程根据内存生成精简AOF 4. 重写完成后父进程将缓冲区内容附加到新AOF末尾 5. 替换旧AOF文件结果重写期间的新操作不会丢失。重写流程图Step 1: fork子进程 │ ▼ Step 2: 子进程读取内存数据生成精简AOF │ ▼ Step 3: 父进程将新写操作记录到重写缓冲区 │ ▼ Step 4: 子进程重写完成通知父进程 │ ▼ Step 5: 父进程将缓冲区内容追加到新AOF末尾 │ ▼ Step 6: 原子性替换旧AOF文件四、RDB持久化Redis Database原理通过fork子进程将内存中的数据对象按照编码格式直接持久化到RDB文件。┌─────────────────────────────────┐ │ Redis父进程 │ │ 内存数据各种编码格式 │ └─────────────────────────────────┘ │ fork ▼ ┌─────────────────────────────────┐ │ RDB持久化子进程 │ │ 读取内存 → 按编码格式序列化 │ │ → 写入RDB文件 │ └─────────────────────────────────┘特点文件小存储的是数据值不是命令恢复快直接加载数据无需重放命令可能有数据丢失依赖持久化策略如5分钟持久化一次触发方式方式说明手动触发SAVE同步阻塞或BGSAVE异步自动触发按配置策略如5分钟1次、1分钟1000次等关机时Redis shutdown 时默认执行BGSAVERDB的编码问题Redis内部数据有多种编码方式int、raw、ziplist、ht等RDB持久化时会根据具体编码格式序列化。五、RDB-AOF混用持久化原理同时开启RDB和AOF取两者优点。1. fork子进程 2. 子进程根据内存生成RDB文件 3. 持久化期间父进程将写操作记录到AOF重写缓冲区 4. 子进程RDB持久化完成 5. 父进程将缓冲区内容追加到AOF文件 6. 最终得到RDB文件 增量AOF恢复逻辑Redis启动时 如果AOF开启 → 优先使用AOF恢复数据最新 否则 → 使用RDB恢复优缺点维度RDB-AOF混用优点RDB快速加载 AOF增量保证最新缺点复杂度高运维成本增加六、持久化方案对比维度RDBAOF混用文件大小小大中数据完整性取决于策略取决于策略好恢复速度快慢快持久化代价较高fork阻塞风险较低后台追加中数据丢失风险较高快照间隔较低every-sec丢1秒低复杂度低中高七、持久化策略选择建议场景推荐策略缓存场景允许少量数据丢失RDB需要较高数据可靠性AOFevery-sec关键业务数据AOFalways或 RDB-AOF混用数据量不大频繁持久化AOF重写 every-sec生产环境推荐配置# AOF配置 appendonly yes appendfsync every-sec aof-rewrite-inject-snappy yes # RDB配置可选用于备份 save 900 1 save 300 10 save 60 10000八、写时复制面试追问问题答案为什么fork采用写时复制而不是全量复制全量复制物理内存耗时过长会阻塞父进程fork的瞬间子进程能看到多少数据与父进程完全相同的内存快照什么时候会真正复制物理页父进程发生写操作时子进程修改了数据会影响父进程吗不会COW机制保证父子进程地址空间隔离九、相关题目题目难度Redis AOF三种刷盘策略对比Redis RDB持久化原理写时复制COW机制详解AOF重写流程与重写缓冲区总结持久化核心 ┌─────────────────────────────────────┐ │ fork 写时复制 → 子进程持久化 │ │ 父进程继续服务不阻塞 │ └─────────────────────────────────────┘ AOF vs RDB AOF → 命令追加数据完整但文件大 RDB → 数据快照文件小但有丢失窗口 最佳实践 缓存场景 → RDB 关键业务 → AOFevery-sec 最高可靠 → RDB-AOF混用根据零声教育教学写作https://github.com/0voice