Redis 的持久化
Redis 是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。
Redis 提供了2个不同形式的持久化方式:
- RDB(Redis DataBase)
- AOF(Append Of File)
RDB(Redis DataBase)
在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里。
Redis 会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。RDB 的缺点是最后一次持久化后的数据可能丢失。
- Fork 的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
- 在 Linux 程序中,fork() 会产生一个和父进程完全相同的子进程,但子进程在此后多会 exec 系统调用,出于效率考虑,Linux 中引入了 “写时复制技术”。
- 一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
RDB 持久化流程
dump.rdb 文件
在 redis.conf 中配置文件名称,默认为 dump.rdb
# The filename where to dump the DB
dbfilename dump.rdb
rdb 文件的保存路径,也可以修改。默认为 Redis 启动时命令行所在的目录下 dir “/myredis/”
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir ./
RDB 快照配置策略
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving completely by commenting out all "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
# 配置文件中默认的快照配置
save 900 1 # 900秒内修改1次则出发RDB
save 300 10 # 300秒内修改10次则出发RDB
save 60 10000 # 60秒内修改10000次则出发RDB
RDB 快照触发机制
- save 的规则满足的情况下,会产生 dump.rdb 文件。
- 执行 flushall 命令,也会产生 dump.rdb 文件,但里面是空的,无意义。
- 退出 Redis 的时候也会产生 dump.rdb 文件。
RDB 快照恢复操作
将备份文件(dump.rdb)移动到 Redis 安装目录并启动服务,备份数据会直接加载。
可通过 config get dir
查询 rdb 文件的目录。
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"
命令 save VS bgsave
RDB 是整合内存的压缩过的 Snapshot,RDB 的数据结构,可以配置复合的快照触发条件。
如果想禁用 RDB 持久化的策略,只要不设置任何 save 指令,或者给 save 传入一个空字符串参数也可以。
若要修改完毕需要立马生效,可以手动使用 save 命令!立马生效 。
其它配置参数解析
# 当 Redis 无法写入磁盘的话,直接关掉 Redis 的写操作。推荐 yes
stop-writes-on-bgsave-error yes
# 对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,Redis 会采用 LZF 算法进行压缩。
# 如果不想消耗 CPU 来进行压缩的话,可以设置为关闭此功能。推荐yes
rdbcompression yes
# 在存储快照后,还可以让 Redis 使用 CRC64 算法来进行数据校验,检查完整性。
# 但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。推荐yes
rdbchecksum yes
RDB 的优缺点
优点:
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高更适合使用
- 节省磁盘空间
- 恢复速度快
缺点:
- Fork 的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
- 虽然 Redis 在 fork 时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能
- 在备份周期在一定间隔时间做一次备份,所以如果 Redis 意外 down 掉的话,就会丢失最后一次快照后的所有修改
AOF(Append Only File)
以日志的形式来记录每个写操作(增量保存),将 Redis 执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,Redis 启动之初会读取该文件重新构建数据,换言之,Redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
AOF 持久化流程
- 客户端的请求写命令会被 append 追加到 AOF 缓冲区内;
- AOF 缓冲区根据AOF持久化策略 [always,everysec,no] 将操作 sync 同步到磁盘的 AOF 文件中;
- AOF 文件大小超过重写策略或手动重写时,会对 AOF 文件 rewrite 重写,压缩 AOF 文件容量;
- Redis 服务重启时,会重新 load 加载 AOF 文件中的写操作达到数据恢复的目的;
AOF 配置参数解析
# 是否以 append only 模式作为持久化方式,默认是不开启的
# Redis 默认使用的是 rdb 方式持久化,这种方式在许多应用中已经足够用了
appendonly no
# appendfilename AOF 文件名称
appendfilename "appendonly.aof"
# appendfsync aof 持久化策略的配置
# no 表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快。
# always 表示每次写入都执行 fsync,以保证数据同步到磁盘。
# everysec 表示每秒执行一次 fsync,可能会导致丢失这1s数据。
appendfsync everysec
# 重写时是否可以运用 Appendfsync,用默认 no 即可,保证数据安全性
no-appendfsync-on-rewrite no
# 设置重写的基准值
auto-aof-rewrite-percentage 100
# 设置重写的基准值
auto-aof-rewrite-min-size 64mb
AOF 启动/修复/恢复
AOF 的备份机制和性能虽然和 RDB 不同,但是备份和恢复的操作同 RDB 一样,都是拷贝备份文件,需要恢复时再拷贝到 Redis 工作目录下,启动系统即加载。
正常恢复:
- 修改默认的 appendonly no,改为 yes
- 将有数据的 aof 文件复制一份保存到对应目录(查看目录:
config get dir
) - 恢复:重启 Redis 然后重新加载
异常恢复:
- 修改默认的 appendonly no,改为 yes
- 如遇到 AOF 文件损坏,通过
/usr/local/bin/redis-check-aof--fix appendonly.aof
进行恢复 - 备份被写坏的 AOF 文件
- 恢复:重启 Redis 然后重新加载
Rewrite 压缩
1、Rewrite 是什么
AOF 采用文件追加方式,文件会越来越大,为避免出现此种情况,新增了重写机制,当 AOF 文件的大小超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩, 只保留可以恢复数据的最小指令集,可以使用命令 bgrewriteaof
。
2、重写原理
AOF 文件持续增长而过大时,会 fork 出一条新进程来将文件重写(也是先写临时文件最后再 rename),遍历新进程的内存中数据,每条记录有一条的 Set 语句。重写 AOF 文件的操作,并没有读取旧的 AOF 文件,这点和快照有点类似。
3、触发机制
Redis 会记录上次重写时的 AOF 大小,默认配置是当 AOF 文件大小是上次 rewrite 后大小的已被且文件大于 64M 的触发。
AOF 的优缺点
优点:
- 备份机制更稳健,丢失数据概率更低。
- 可读的日志文本,通过操作AOF稳健,可以处理误操作。
缺点:
- 比起 RDB 占用更多的磁盘空间。
- 恢复备份速度要慢。
- 每次读写都同步的话,有一定的性能压力。
- 存在个别 Bug,造成恢复不能。
总结(Which one)
AOF 和 RDB 同时开启
- 同时开启两种持久化方式,在这种情况下,当 Redis 重启的时候会优先载入 AOF 文件来恢复原始的数据,因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整。
- RDB 的数据不实时,同时使用两者时服务器重启也只会找 AOF 文件。那要不要只使用 AOF 呢? 建议不要,因为 RDB 更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有 AOF 可能潜在的Bug,留着作为一个万一的手段。
AOF 和 RDB 用哪个好
官方推荐两个都启用。如果对数据不敏感,可以选单独用 RDB。不建议单独用 AOF,因为可能会出现 Bug。如果只是做纯内存缓存,可以都不用。
- RDB 持久化方式能够在指定的时间间隔能对你的数据进行快照存储。
- AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF 命令以 Redis 协议追加保存每次写的操作到文件末尾。
- Redis还能对 AOF 文件进行后台重写,使得 AOF 文件的体积不至于过大。
- 只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
AOF 和 RDB 性能建议
- 因为 RDB 文件只用作后备用途,建议只在 Slave 上持久化 RDB 文件,而且只要 15 分钟备份一次就够了,只保留
save 900 1
这条规则。 - 如果使用 AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只 load 自己的 AOF 文件就可以了。
- 代价一是带来了持续的 IO,二是 AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。
- 只要硬盘许可,应该尽量减少 AOF rewrite 的频率,AOF 重写的基础大小默认值 64 M太小了,可以设到 5G 以上。
- 默认超过原大小 100% 大小时重写可以改到适当的数值。