Redis持久化 - RDB&AOF

Redis 持久化有两个选项,分别是 AOF 日志 和 RDB 快照, 两个持久化方式可以让 redis 宕机后基本(为什么不是一定)不丢失数据, 同时也是 Redis 主从同步的基础, 今天让我们一起学习一下两种持久发方式有啥不同.什么场景下应该使用那种方式吧!

AOF 日志

AOF 是通过记录执行过的 Redis 命令来保存 Redis 数据的, 和主流的数据库(例如 Mysql 通过写前日志和两阶段提交,实现数据和逻辑的一致性)所采用的写前日志(WAL)不同, AOF 是先执行 Redis 命令, 执行成功后写入,

优缺点

Redis 选择先执行命令后写入主要有两个优点,

  1. 不用判断 Redis 命令的语法是否正确, 执行成功后的命令一定是正确的
  2. 执行命令后写日志, 不会阻塞当前的写操作

当然使用这种方式也存在两个潜在的风险点,

  1. 写入数据后宕机, 日志丢失
  2. 写日志操作仍在主进程上操作, 虽然不会阻塞当前命令, 但是仍然回阻塞下一次查询

写回策略

从上面两个风险点可以发现, 问题都出现在 AOF 写回磁盘的时候, 所以为了避免写入日志对于 redis 性能的影响. 给我们提供了三个选择, 也就是 appendfsync 这个参数的三个可选值

  • Always: 同步写回, 也就是命令执行之后马上写入磁盘, 可以做到基本不丢数据, 但是因为每次都要写入磁盘所以性能会受到较大影响
  • Everysec: 每秒写回, 可以先把日志记录到内存的缓冲区, 然后每隔一秒保存到磁盘上, 算是再性能和数据之间保持了一个平衡
  • No: 操作系统控制写回, redis 只把日志记录到内存缓冲区, 由操作系统决定何时将数据刷写到盘上

三种写回粗略,各有利弊,没法做到完美, 要跟据实际场景才能作出选择, 想要性能高同时对数据不敏感, 就选择 No, 想要数据安全丢失的可能性最小,就使用Always, 允许数据部分丢失且对性能要求又较高时就选Everysec

AOF 重写机制

为了避免 AOF 日志文件过大对性能造成影响, Redis 提供了一个把多条命令合并成一条减少 AOF 文件的体积,这个机制是如何压缩 AOF 体积的呢?

我们知道 AOF 是再命令执行结束后追加到文件末尾的, 也就是说当我们多次反复修改一个 Key 的时候AOF 里面也会记录多条命令, 所以,压缩AOF 文件实际上就是把多个命令合并为一条, 记录最后的结果状态,需要恢复的时候也只需要执行这一条命令就可以了. 这样就大大减少了 AOF 的体积, 不过要完成所有合并所有命令, 需要遍历 AOF 记录, 并记录数据的最后状态,想想都麻烦, 如果这个操作需要阻塞Redis, 那是绝对不能接受的, 那 Redis 是如何实现的呢?

AOF 重写过程

既然阻塞主线程不能接受, 所以实际上redis 在执行 AOF 命令的时候, 主线程会 fork (但是fork本身阻塞进程)出一个 叫做 bgrewriteaof 的子进程, fork 会把主线程的内存数据 拷贝 (写实复制)一份给Bgrewriteaof, bgrewriteaof 根据拷贝内存中的数据创建新的 aof 日志, 这样就避免了阻塞主线程的问题,

但是这又带来了新的问题, 由于重写过程不会阻塞主进程,所以主进程仍然可以处理任务, 这个时候如果有新的写操作, 就会导致主进程 和 bgrewriteaof 进程的数据不同

原来 Redis 在 AOF重写过程中会记录两个日志: 除正常记录AOF 日志外, Redis 还会把日志记录到AOF 重写缓冲区, 等重写日志完成之后, 再把重写缓冲区的记录追加到重写日志的后面,这样既保证了宕机后, redis可以读取现有的AOF 日志恢复,又保证了在重写完成后 AOF 也不会丢失记录.

RDB 快照

主从同步


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!