Redis 的持久化机制

Redis 的持久化(Persistence)机制可以有效避免 redis 服务器在遇到故障时数据丢失的问题,发生故障重启后重新载入持久化的内容就可以恢复数据。redis 有两种持久化机制 RDB 和 AOF。

持久化的一些概念

持久化一般有两种实现方式,一种是类似 MySQL 的 dump 命令的快照方式,这种方式每次调用会将数据库中的全部内容都一次性写入到硬盘中,恢复的时候也可以一次性将全部数据恢复出来。 另一种则是类似于 MySQL 的 Binlog 的方式,每当数据库内容更新时,记录下所有写操作的执行,恢复时,按照日志的顺序把所有的操作再执行一遍就可以恢复原来的数据。

RDB(Redis DataBase) 快照方式

RDB 是利用快照实现的一种持久化技术,在 redis 中,内存中的数据经过 RDB 持久化后,会被保存到硬盘上的RDB二进制文件中,当我们需要恢复数据时,重新加载到内存中即可。 在进行快照时,如果系统中存在陈旧的快照,那么 RDB 会先新建快照,完成后再替换陈旧的快照。 每次持久化的时间复杂度为 O(n)。

RDB 的触发方式

save 和 bgsave

save 和 bgsave 都可以通过用户主动调用的方式来完成数据的持久化,区别是save 是一个同步命令,执行时会阻塞 redis 的主线程,而 redis 又是单进程单线程的,这就会导致 save 执行的过程中,其他的指令只能排队阻塞等待执行。 bgsave 则是通过 fork() 系统调用新建一个子进程在后台完成数据持久化任务,不会阻塞主线程。
他们的主要区别如下:

save bgsave
阻塞? 是(调用 fork() 时)
优点 不需要额外消耗内存 不会阻塞客户端其他命令
缺点 需要阻塞,部分场景不允许 fork消耗系统资源

自动触发

redis 会根据配置文件自动触发 bgsave 命令完成数据的持久化,通常情况下在 redis.conf 文件中我们会看到下面这样的配置项

save 900 1
save 300 10
save 60 10000

save N M表示在 N 秒之内,redis 至少发生 M 次修改则 redis 抓快照到磁盘。 这个三条记录只要有一个满足要求就执行 bgsave 命令。一般项目中不启用自动触发

其他的触发方式(容易忽略的)

  • 全量复制(如主从复制时)
  • debug reload
  • shutdown

AOF(Append Only File) 日志方式

RDB出现的问题:

  1. 时间复杂度为O(n),耗时耗性能
  2. 不可控,丢失数据,只有固定的时间点的数据会被持久化

AOF的原理: 其实就是记录每一条命令,不过是保存在专有的 AOF 格式。AOF 的写入几乎是实时的。

AOF 的写入策略

从内存中将数据复制到硬盘扇区是一项较为耗时的操作,redis 的 AOF 为我们提供了三种决定写入时机的策略,分别是 always, everysec 和 no。

always 策略

每次执行命令都会调用 fsync 将命令写入到日志文件中,大数据量时非常慢但是十分安全。这种方式 IO 开销很大,对于一般的 sata 盘只有几百 TPS。

everysec 策略

每秒将 redis 缓冲区中缓存的命令调用 fsync 写入到 aof 日志文件中,速度快了很多但是可能会丢失最近一秒的数据。

no 策略

操作系统决定何时应该刷新,不可控

AOF 重写

当我们写入的命令很多之后,aof文件就会变得非常大,为了尽可能优化aof文件的大小,加快恢复的速度,会对aof文件进行重写。

AOF 重写的两种方式

  1. bgrewriteaof 命令(利用fork异步进行)
  2. 自动重写,有两个配置项,auto-aof-rewrite-min-size,表示需要进行重写的尺寸和 auto-aof-rewrite-percentage,表示aof文件的增长率。同时满足两个条件时则 redis 会自动进行重写。

RDB 和 AOF 的对比

命令 RDB AOF
恢复优先级
体积
恢复速度
数据安全性 丢数据 根据策略决定
轻重