前言

Redis的AOF日志记录的操作命令,而非实际数据,恢复数据时需要把日志全量执行一遍;所以当AOF日志足够大时,必然造成Redis数据恢复缓慢。Redis为解决这个问题,故而增加了RDB快照。RDB快照记录的是某一瞬间的内存数据(实际数据),因此在数据恢复时,RDB快照恢复数据比AOF的效率高些,因为RDB只需将数据读入内存即可,不需要想AOF那样还需要额外执行命令才能恢复数据。

RDB持久化

RDB快照进行时会阻塞线程吗?

Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave,他们的区别就在于是否在「主线程」里执行:

  • 执行了 save 命令,就会在主线程生成 RDB 文件,由于和执行操作命令在同一个线程,所以如果写入 RDB 文件的时间太长,会阻塞主线程
  • 执行了 bgsave 命令,会创建一个子进程来生成 RDB 文件,这样可以避免主线程的阻塞

Redis 还可以通过配置文件的选项来实现每隔一段时间自动执行一次 bgsave 命令,默认会提供以下配置:

1
2
3
save 900 1
save 300 10
save 60 10000

虽然命令选项名叫 save,但实际上执行的是 bgsave 命令,就是会创建子进程来生成 RDB 快照文件。 只要满足上面条件的任意一个,就会执行 bgsave,它们的意思分别是:

  • 900 秒之内,对数据库进行了至少 1 次修改;
  • 300 秒之内,对数据库进行了至少 10 次修改;
  • 60 秒之内,对数据库进行了至少 10000 次修改。

这里提一点,Redis 的快照是全量快照,也就是说每次执行快照,都是把内存中的「所有数据」都记录到磁盘中。所以执行快照是一个比较重的操作,如果频率太频繁,可能会对 Redis 性能产生影响。如果频率太低,服务器故障时,丢失的数据会更多。

RDB快照进行时能修改数据吗?

可以,在执行 bgsave 过程中,Redis 依然可以继续处理操作命令的,也就是数据是能被修改的,关键的技术就在于写时复制技术(Copy-On-Write, COW)。

执行 bgsave 命令的时候,会通过 fork() 创建子进程,此时子进程和父进程是共享同一片内存数据的,因为创建子进程的时候,会复制父进程的页表,但是页表指向的物理内存还是一个。

  • 如果主线程执行读操作,则主线程和 bgsave 子进程互相不影响

  • 如果主线程执行写操作,则被修改的数据会复制一份副本,然后 bgsave 子进程会把该副本数据写入 RDB 文件,在这个过程中,主线程仍然可以直接修改原来的数据

Redis为什么会有混合持久化?

RDB 优点是数据恢复速度快,但是快照的频率不好把握。频率太低,丢失的数据就会比较多,频率太高,则会影响性能。

AOF 优点是丢失数据少,但是当日志量过大时数据恢复不快。

为了集成了两者的优点, Redis 4.0 提出了混合使用 AOF 日志和内存快照,也叫混合持久化,既保证了 Redis 重启速度,又降低数据丢失风险。

混合持久化工作在 AOF 日志重写过程,当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。也就是说,使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据

优点:

  • Redis重启加载数据的时候,速度会很快

  • 数据丢失更少

缺点:

  • 由于AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变差
  • 兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不兼容 Redis 4.0 之前的版本了