Skip to content

Redis 持久化

Redis 是内存数据库,如果想要将数据写入磁盘就需要配置持久化。Redis 提供了两种形式的持久化:

  1. RDB(Redis Database): 根据指定时间间隔执行数据集的时间点快照
  2. AOF(Append Only File): 记录服务器接收到的每个写操作,然后可以在重启服务时再次重复这些操作来重建原始数据集

Tips

默认是没有开启持久化的,在一个实例里面能够组合使用 AOF 和 RDB

RDB 和 AOF 的优缺点

最初 Redis 只有 RDB 一个持久化选项,它具有几个优点:

  • 提供了非常紧凑的单文件基于特定时间的 Redis 数据的快照,因此它非常适合用于备份数据,例如实现每小时归档一次 RDB 文件,30 天内每天保存一个 RDB 快照等
  • RDB 非常适用于灾难恢复,因为它是一个紧凑的单文件数据快照,可以定期传输到远程的数据中心中,如果发生灾难能够快速恢复
  • RDB 最大限度的保证 Redis 的性能,在执行 RDB 持久化时 Redis 会分叉一个新的进程来保存,即主线程不会执行磁盘 IO 这样的阻塞操作

而 RDB 的缺点也很明显:

  • 他无法最大程度的减少数据丢失的可能性,因为他是基于时间的快照,如果两个时间间隔内存在大量并发时服务崩溃,最新时间的数据将全部丢失
  • RDB 需要经常 fork 新的进程来执行持久化保存,如果数据集非常大 fork 的过程非常耗时甚至会导致服务器阻塞(仅仅 fork 过程,fork 后的磁盘 IO 不会阻塞主线程)。

而 AOF 就是为了解决 RDB 的缺点而存在的,AOF 将所有的写操作(包括插入、更新和删除)追加到日志后,因此如果服务崩溃仅仅最后一条数据会丢失从而保证数据的完整性,并且追加操作远比 fork 操作要轻度的多。

当然 AOF 的缺点也非常明显,对于相同的数据集,AOF 文件通常比 RDB 文件大的多,并且它是一条条语句恢复起来的速度也比 RDB 要慢的多。

两种持久化的选择

一般来讲,如果想要和数据库一样的数据安全性,应该同时开启这两种数据持久化方式。

如果可以容忍灾难发生的最近几分钟的数据丢失,通常只需要开启 RDB 就可以了。

通常不建议只开启 AOF,RDB 是数据备份以及灾难恢复的最佳方式。

配置 RDB

Text Only
# save <seconds> <changes> [<seconds> <changes> ...]
# 如果给定 seconds 秒中执行了 changes 次写操作将执行保存
# 可以同时设置多个
# 如果要禁用 RDB 就可以
# save ""

save 3600 1 300 100 60 10000
# 上面的设置在三种情况下备份
# 1. 1 小时中至少执行了 1 次操作将备份
# 2. 5 分钟内至少执行了 100 次操作将备份
# 3. 1 分钟内至少执行了 10000 次操作将备份

# 配置 RDB 文件存储路径
# 注意是路径而不是名字
dir /var/lib/redis/

# 定义 RDB 文件的文件名
# 因此全路径就是 dir/dbfilename
dbfilename dump.rdb

# 压缩支持,默认 RDB 启用压缩,如果是性能优先于磁盘可以禁用它
rdbcompression no

配置 AOF

Text Only
# 开启 AOF 的支持
appendonly yes

# 配置 AOF 文件名
appendfilename "appendonly.aof"

# 配置 AOF 文件存储路径
# 注意是路径而不是名字
dir /var/lib/redis/

# AOF 刷新策略
appendfsync always
# fsync: 每次写操作后立即写入磁盘,最安全但性能影响最大
# everysec: 每秒写入一次
# no: 不主动调用,由操作系统自行决定,性能最好但是安全性不太行

AOF 文件随着时间的推移会不断增加,Redis 提供了一种机制来自动重写 AOF 文件,以减少文件大小并提高恢复效率:

Text Only
# 配置自动重写的条件
# AOF 文件比上一次重写后增大 100% 且文件大小超过 64MB 时触发
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

当写入 AOF 文件时服务器崩溃了,或者写入 AOF 文件时磁盘满了。发生这种情况时 AOF 文件中的最后一个命令可能会截断。此时如果恢复数据会提示:

Bash
* Reading RDB preamble from AOF file...
* Reading the remaining AOF tail...
# !!! Warning: short read while loading the AOF file !!!
# !!! Truncating the AOF at offset 439 !!!
# AOF loaded anyway because aof-load-truncated is enabled

此时我们可以通过开启下面的选项来强制执行:

Text Only
# 启动时允许加载截断的 AOF 文件
aof-load-truncated yes

Tips

在老版本可能需要手动使用 redis-check-aof --fix <filename> 来恢复。该工具在新版本下用于修复损坏(不仅仅是截断)的 aof 文件

手动备份

上面的配置都是自动生成持久化文件,我们也可以手动为特定时间节点的数据执行备份。

对于 RDB 文件进行手动备份:

Bash
# 手动触发快照,他会阻塞 Redis 进程直到快照完成
redis-cli SAVE

# 手动触发快照,他不会阻塞 Redis 进程直到快照完成
redis-cli BGSAVE

他会生成 dir/rdbfilename 文件,通常建议在其他地方备份该文件并命名为时间节点是一个很好的习惯。

对于 AOF 文件进行手动备份,非常简单只需要开启 AOF,然后复制 dir/appendfilename 文件到其他位置即可。

Tips

通常一个好的习惯就是通过 cron 等定时工具来每天备份一个文件(30 天周期)

灾难恢复

持久化的目的就是为了在遇到意外情况下对 redis 数据库进行恢复。

当同时开启 AOF 和 RDB 时,Redis 在灾难恢复时会优先使用 AOF 文件来进行恢复,这是因为 AOF 文件的记录具有更细的颗粒度。但是它往往非常慢。如果对数据时效性要求不那么高可以通过 RDB 来进行恢复:

  1. 首先禁用 AOF 文件加载(appendonly no)
  2. 之后执行 Redis 恢复
  3. 之后可以重新在 client 中执行 CONFIG SET appendonly yes 来开启 AOF 持久化

参考