Redis持久化

官方文档地址:https://redis.io/topics/persistence

Redis 的读写操作都是在内存中,所以 Redis 性能才会高。那么在内存中带来的问题就是重启后会数据丢失,Redis如何实现持久化功能的呢?

注意共有三种数据持久化的方式:

  • AOF 日志:(append-only file,只追加文件)每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
  • RDB 快照(snapshotting,快照):将某一时刻的内存数据,以二进制的方式写入磁盘;
  • AOF 和 RBD混合持久化方式

AOF日志

AOF 日志文件其实就是普通的文本,将每一次的写操作命令都记录到该文本中,就是AOF日志。

值得注意的是,AOF日志是先执行完命令再记录日志

这样的好处是:

  1. 避免额外的检查开销,AOF 记录日志不会对命令进行语法检查;
  2. 在命令执行完之后再记录,不会阻塞当前的命令执行。

这样也带来了风险:

  1. 如果刚执行完命令 Redis 就宕机会导致对应的修改丢失;
  2. 可能会阻塞后续其他命令的执行(AOF 记录日志是在 Redis 主线程中进行的)。

基本的AOF工作流程如下图:

AOF写回策略

在同步操作中,AOF 缓冲区根据对应的持久化方式( fsync 策略)向硬盘做同步 操作。这些 fsync 策略称为写回策略, redis.conf 配置文件中的 appendfsync下配置。一共有以下3种:

  1. Always:每次主线程进行文件写入(write) 操作后,后台线程立即会调用 fsync 函数同步 AOF 文件(刷盘)。fsync 完成后线程返回,这样会严重降低 Redis 的性能。(高可靠场景下使用)
  2. Everysec:主线程调用 write 执行写操作后立即返回,由后台线程( aof_fsync 线程)每秒钟调用 fsync 函数(系统调用)同步一次 AOF 文件。
  3. No:主线程调用 write 执行写操作后立即返回,让操作系统决定何时进行同步,Linux 下一般为 30 秒一次。(高性能场景下使用)

以上3 种持久化方式的主要区别在于 fsync 同步 AOF 文件的时机(刷盘)

AOF重写策略

如上图的第四个框图,当AOF文件越来越大时,超过设定的某个阈值时,Redis 能够在后台自动重写 AOF 产生一个新的 AOF 文件,这个新的 AOF 文件和原有的 AOF 文件所保存的数据库状态一样,但体积更小。

如何实现重写?

AOF 重写机制是在重写时,读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的 AOF 文件」,等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件。

比如在没有使用重写机制前,假设前后执行了「*set age 18* 」「*set age 20*」这两个命令的话,就会将这两个命令记录到 AOF 文件。重写之后,则只保留「set age 20」。

重写策略会新建一个文件来进行重写操作,重写成功再覆盖原AOF文件,重写失败则直接删除失败的AOF文件,不会对原AOF文件产生影响。

后台重写

由于 AOF 重写会进行大量的写入操作,为了避免对 Redis 正常处理命令请求造成影响,Redis 将 AOF 重写程序放到子程里执行,即在后台进行重写。

子进程如何保持与主进程的数据同步?

后台重写的AOF 文件重写期间,Redis 还会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新 AOF 文件期间,记录服务器执行的所有写命令。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新的 AOF 文件保存的数据库状态与现有的数据库状态一致。最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作。

RDB快照

RDB快照是Redis默认的持久化方式。

Redis 可以通过创建快照来获得存储在内存里面的数据在 某个时间点 上的副本。Redis 创建快照之后,可以对快照进行备份。快照是二进制数据。

redis.conf中,可以通过save (int)time (int)num 的方式来RDB快照的方式进行配置。例如:

1
2
3
save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发bgsave命令创建快照。

save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发bgsave命令创建快照。

注意:命令是save,实际执行的是bgsave。bgsave快照可以fork 出一个子进程,在子进程执行快照,不会阻塞 Redis 主线程,默认选项。

Redis 的快照是全量快照,也就是说每次执行快照,都是把内存中的「所有数据」都记录到磁盘中。

RDB的优点是恢复速度快,直接恢复快照中的数据就行。

所以当快照太频繁时,可能对Redis性能产生影响。而快照频率太低时,又容易丢失太多数据。这就是RDB的缺点:可能比AOF日志丢失更多的数据(通常可能设置至少 5 分钟才保存一次快照)

AOF 和 RBD混合持久化方式

由于 RDB 和 AOF 各有优势,于是,Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。

如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。也就是说,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据

这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。

缺点是, AOF 里面的 RDB 部分是压缩格式不再是 AOF 格式,可读性较差。

如何选择 RDB 和 AOF?

以下是官网给出的比较:

  • Redis 保存的数据丢失一些也没什么影响的话,可以选择使用 RDB。
  • 不建议单独使用 AOF,因为时不时地创建一个 RDB 快照可以进行数据库备份、更快的重启以及解决 AOF 引擎错误。
  • 如果保存的数据要求安全性比较高的话,建议同时开启 RDB 和 AOF 持久化或者开启 RDB 和 AOF 混合持久化。