Skip to content

Redis Persistence Mechanism

RDB 内存快照

Redis 通过定时执行 RDB 内存快照,不需要每次写指令写磁盘, 这样可以提高 redis 性能,只需要在执行快照的时候写磁盘,保证了快,同时实现了持久化 project

RDB 策略

  • sava: 主线程执行, 阻塞
  • bgsvae: 调⽤ glibc 的函数 fork 产⽣⼀个⼦进程⽤于写⼊ RDB ⽂件,快照持久化完全交给⼦进程来处理,⽗进程继续处理客户端请求,⽣成 RDB ⽂件的默认配置。

Redis 如何完成既可以生成 RDB,又可以接收写指令?

project

Redis 使用操作系统的多进程写时复制技术(Copy On Write) 来实现快照持久化 Redis 在持久化调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求 子进程产生的时候,和父进程共享内存里面的代码段和数据段。 bgsave 子进程可以共享主线程的内存数据,读取主进程的数据写入 RDB 文件 执行 SAVE 命令或者 BGSAVE 命令创建一个 RDB 文件,程序会怼数据库中的键进行检查,过期的键不会被保存到新创建的 RDB 文件 主线程执行写指令修改数据,这个数据会复制一份副本,bgsave 子进程读取这个副本数据写道 RDB 文件

这样保证了快照的完整性,也允许主线程同时对数据进行修改, 避免了对正常业务的影响

过于频繁的执行快照的问题:

  1. 频繁⽣成 RDB ⽂件写⼊磁盘,磁盘压⼒过⼤。会出现上⼀个 RDB 还未执⾏完,下⼀个⼜开始⽣成,陷⼊死循环
  2. fork 出 bgsave ⼦进程会阻塞主线程,主线程的内存越⼤,阻塞时间越⻓

优缺点:

  1. 快照的恢复速度快,但是⽣成 RDB ⽂件频率不好把握,频率过低宕机丢失的数据就会⽐较多;太快,⼜会消耗额外开销
  2. RDB 采⽤⼆进制 + 数据压缩的⽅式写磁盘,⽂件体积⼩,数据恢复速度快。

AOF 写后日志

AOF ⽇志存储的是 Redis 服务器的顺序指令序列,AOF ⽇志只记录对内存进⾏修改的指令记录

写回策略

  1. always: 同步写回,写指令执⾏完毕⽴⻢将 aof_buf 缓冲区中的内容刷写到 AOF ⽂件
  2. everysec: 每秒写回,写指令执⾏完,⽇志只会写到 AOF ⽂件缓冲区,每隔⼀秒就把缓冲区内容同步到磁盘
  3. no: 操作系统控制,写执⾏执⾏完毕,把⽇志写到 AOF ⽂件内存缓冲区,由操作系统决定何时刷写到磁盘

优缺点:

  1. 优点:执⾏成功才记录⽇志,避免了指令语法检查开销。同时,不会阻塞当前「写」指令
  2. 由于 AOF 记录的是⼀个个指令内容,具体格式请看上⾯的⽇志格式。故障恢复的时候需要执⾏每⼀个指令,如果⽇志⽂件太⼤,整个恢复过程就会⾮常缓慢另外⽂件系统对⽂件⼤⼩也有限制,不能保存过⼤⽂件,⽂件变⼤,追加效率也会变低。

AOF 重写机制 就是开辟⼀个⼦进程对内存进⾏遍历转换成⼀系列 Redis 的操作指令,序列化到⼀个新的 AOF ⽇志⽂件中。序列化完毕后再将操作期间发⽣的增量 AOF ⽇志追加到这个新的 AOF ⽇志⽂件中,追加完毕后就⽴即替代旧的 AOF ⽇志⽂件了,瘦身⼯作就完成了 例如: 三条 LPUSH 指令,经过 AOF 重写后⽣成⼀条,对于多次修改的场景,缩减效果更加明显

重写步骤:

  1. Redis 会将重写过程中的接收到的「写」指令操作同时记录到旧的 AOF 缓冲区和 AOF 重写缓冲区,这样重写⽇志也保存最新的操作。等到拷⻉数据的所有操作记录重写完成后,重写缓冲区记录的最新操作也会写到新的 AOF ⽂件中
  2. 每次 AOF 重写时,Redis 会先执⾏⼀个内存拷⻉,⽤于遍历数据⽣成重写记录;使⽤两个⽇志保证在重写过程中,新写⼊的数据不会丢失,并且保持数据⼀致性。

Redis 混合日志模型

  • 重启 Redis 时,我们很少使⽤ rdb 来恢复内存状态,因为会丢失⼤量数据。我们通常使⽤ AOF ⽇志重放,但是重放 AOF ⽇志性能相对 rdb 来说要慢很多,这样在 Redis 实例很⼤的情况下,启动需要花费很⻓的时间。

  • Redis 4.0 为了解决这个问题,带来了⼀个新的持久化选项——混合持久化。将 rdb ⽂件的内容和增量的 AOF ⽇志⽂件存在⼀起。这⾥的 AOF ⽇志不再是全量的⽇志,⽽是⾃持久化开始到持久化结束的这段时间发⽣的增量 AOF ⽇志,通常这部分 AOF ⽇志很小

  • 于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF ⽇志就可以完全替代之前的 AOF 全量⽂件重放,重启效率因此⼤幅得到提升

  • 所以 RDB 内存快照以稍微慢⼀点的频率执⾏,在两次 RDB 快照期间使⽤ AOF ⽇志记录期间发⽣的所有「写」操作

  • 这样快照就不⽤频繁的执⾏,同时由于 AOF 只需要记录两次快照之间发⽣的「写」指令,不需要记录所有的操作,避免出现⽂件过⼤的情况。

日志选择方案

  1. 数据不能丢失时,内存快照和 AOF 的混合使⽤是⼀个很好的选择;
  2. 如果允许分钟级别的数据丢失,可以只使⽤ RDB
  3. 如果只⽤ AOF,优先使⽤ everysec 的配置选项,因为它在可靠性和性能之间取了⼀个平衡

Released under the MIT License.