Redis 是内存型数据库,为了保证数据断电后不丢失,需要将内存中的数据持久化到磁盘上;另一方面,保存中间结果,不必重新计算。

Redis的数据持久化机制是可以关闭的。如果你只把Redis作为缓存服务使用,Redis中存储的所有数据都不是该数据的主体而仅仅是同步过来的备份,那么可以关闭Redis的数据持久化机制。
但通常来说,仍然建议至少开启RDB方式的数据持久化,因为:

  • RDB方式的持久化几乎不损耗Redis本身的性能,在进行RDB持久化时,Redis主进程唯一需要做的事情就是fork出一个子进程,所有持久化工作都由子进程完成
  • Redis无论因为什么原因crash掉之后,重启时能够自动恢复到上一次RDB快照中记录的数据。这省去了手工从其他数据源(如DB)同步数据的过程,而且要比其他任何的数据恢复方式都要快
  • 现在硬盘那么大,真的不缺那一点地方

持久化有 2 种:

  • RDB快照持久化:将存在某一时刻的所有数据都写入磁盘中
  • AOF 持久化:在执行写命令时,将被执行的写命令复制到文件中

Redis 提供的持久化配置选项:

  1. # 快照持久化
  2. save 60 1000
  3. stop-writes-on-bgsave-error yes
  4. rdbcompression no
  5. # AOF 持久化
  6. appendonly yes
  7. appendfsync always # 同步选项
  8. auto-aof-rewrite-percentage 100
  9. auto-aof-rewrite-min-size 64mb
  10. # 共享选项,决定了快照文件和 AOF 文件的保存位置
  11. dir ./

RDB快照持久化

快照持久化是通过创建快照来获得 Redis 存储在内存中数据在某个时间点上的副本。在创建快照后,用户可对快照备份,可将快照留在原地以便重启 Redis 时使用。
采用RDB持久方式,Redis会定期保存数据快照至一个rbd文件中,并在启动时自动加载rdb文件,恢复之前保存的数据。

快照持久化配置

  1. save 900 1
  2. save 300 10
  3. save 60 10000
  4. # 在60秒(1分钟)之后,如果至少有10000个键发生变化,
  5. # Redis 就会自动触发 BGSAVE 命令创建快照。
  6. stop-writes-on-bgsave-error yes
  7. # 表示备份进程出错的时候,主进程就停止接收新的写入操作,
  8. # 是为了保护持久化数据的一致性。
  9. rdbcompression no
  10. # RDB 的压缩设置为 no,因为压缩会占用更多的 CPU 资源。

创建快照的方法

  • BGAVSE 命令
    客户端向 Redis 发送 BGSAVE 命令来创建一个快照。对于支持 BGSAVE 命令的平台来说(基本上所有平台支持,除了Windows平台),Redis 会调用 fork 来创建一个子进程,然后子进程负责将快照写入硬盘,而主进程则继续处理命令请求
  • 用户设置 save 配置选项
    1. save 60 10000
    2. # 从 redis 最近一次创建快照之后算起,满足 “60 s 内 10000 次写入”,Redis 会自动触发 BGSAVE 命令

RDB的优点:

  • 对性能影响最小。Redis在保存RDB快照时会fork出子进程进行,几乎不影响Redis处理客户端请求的效率。
  • 每次快照会生成一个完整的数据快照文件,所以可以辅以其他手段保存多个时间点的快照(例如把每天0点的快照备份至其他存储媒介中),作为非常可靠的灾难恢复手段。
  • 使用RDB文件进行数据恢复比使用AOF要快很多。

RDB的缺点:

  • 快照是定期生成的,所以在Redis crash时或多或少会丢失一部分数据。
  • 如果数据集非常大且CPU不够强(比如单核CPU),Redis在fork子进程时可能会消耗相对较长的时间(长至1秒),影响这期间的客户端请求。

存在的问题

  • 如果系统发生故障,将会丢失最近一次创建快照之后的数据
  • 如果数据量很大,保存快照的时间会很长

AOF 持久化

AOF 持久化将被执行的写命令写到 AOF 文件末尾,记录数据发生的变化。在Redis重启时,会把AOF文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新。

文件包含的所有写命令,就可恢复 AOF 文件所记录的数据。

默认情况下,Redis 没有开启 AOF(append only file)方式的持久化,可以通过 appendonly 参数开启:

  1. appendonly yes

日志持久化配置

  1. appendonly yes
  2. appendfsync always # 同步选项
  3. auto-aof-rewrite-percentage 100
  4. auto-aof-rewrite-min-size 64mb

同步选项

使用 AOF 持久化需要设置同步选项,从而确保写命令什么时候会同步到磁盘文件上。
AOF提供了三种fsync配置,always/everysec/no,通过配置项[appendfsync]指定:

  • appendfsync no:不进行fsync,将flush文件的时机交给OS决定,速度最快
  • appendfsync always:每写入一条日志就进行一次fsync操作,数据安全性最高,但速度最慢
  • appendfsync everysec:折中的做法,交由后台线程每秒fsync一次 | 同步选项 | 同步频率 | 说明 | | —- | —- | —- | | always | 每个 Redis 写命令都要同步写入磁盘 | 当系统发生崩溃时,丢失的数据减到最少;
    需要对磁盘大量写入,速度会受到磁盘限制 | | everysec | 每秒执行一次同步,显示地将多个写命令同步到磁盘 | 性能上和不使用任何持久化特性时相差无几,
    可保证数据即使出现系统崩溃,用户也最多只会丢失 1 秒内产生的数据 | | no | 由操作系统来决定何时进行同步 | 不会对 Redis 性能产生影响,但系统崩溃将导致 Redis 丢失不定量的数据,
    若用户写入磁盘处理写入速度不够快,当缓冲区被等待写入磁盘的数据填满时,Redis 写入操作会被阻塞,并导致 Redis 处理命令请求变慢 |

重写 / 压缩 AOF 文件

AOF 持久化存在的问题:

  • 随着 Redis 不断运行,AOF 文件的体积会不断增长,占用更多的磁盘空间
  • 若 AOF 文件体积非常大,则恢复的时间可能会比较长

为了解决 AOF 文件不断增大的问题,我们采用重写 / 压缩 AOF 文件的方式:

用户 Redis 发送 BGREWRITEAOF 命令,通过移除 AOF 文件中冗余命令来重写 AOF 文件来减小 AOF 文件的体积,只保留能够把数据恢复到最新状态的最小写操作集。
注意:(新的 AOF 文件和原有的 AOF 文件所保存的数据状态是一致的,但是体积更小)。

AOF rewrite可以通过BGREWRITEAOF命令触发,也可以配置Redis定期自动进行

  1. auto-aof-rewrite-percentage 100
  2. auto-aof-rewrite-min-size 64mb
  3. // Redis在每次AOF rewrite时,会记录完成rewrite后的AOF日志大小,
  4. // 当AOF日志大小在该基础上增长了100%后,自动进行AOF rewrite。
  5. // 同时如果增长的大小没有达到64mb,则不会进行rewrite。

AOF的优点:

  • 最安全,在启用appendfsync always时,任何已写入的数据都不会丢失,使用在启用appendfsync everysec也至多只会丢失1秒的数据。
  • AOF文件在发生断电等问题时也不会损坏,即使出现了某条日志只写入了一半的情况,也可以使用redis-check-aof工具轻松修复。
  • AOF文件易读,可修改,在进行了某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据。

AOF的缺点:

  • AOF文件通常比RDB文件更大
  • 性能消耗比RDB高
  • 数据恢复速度比RDB慢

BGREWRITEAOF 原理:

image.png

Redis 维护 AOF 重写缓冲区和 AOF 缓冲区。子进程创建新的 AOF 文件期间,记录服务器执行的所有写命令会同时写入 2 个缓冲区中,使得新旧两个 AOF 文件中所保存的数据状态一致。

对比

持久化方式 优点 缺点
快照持久化 文件小,恢复快 会丢失最近一次生成快照后写入的数据;
是压缩文件,可读性较差
AOF 持久化 可读性好;数据不易丢失(丢失 1 秒内产生的数据) 文件体积大,占用磁盘空间;
恢复时间长

优化

Redis 4.0 以后将快照和 AOF 混合持久化(默认关闭,使用 aof-user-rdb-preamble开启),AOF 重写时将快照写入 AOF 文件开头。

这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据,当然缺点也是有的, AOF 里面的 RDB 部分是压缩格式不再是 AOF 格式,可读性较差。