1-Redis - 持久化
about
所谓持久化,就是将缓存的数据刷写到磁盘,达到持久化和数据恢复的目的。
在Redis中,有RDB快照(snapshotting)和AOF(appendonly-file)两种持久化方式。
我们分别来看看。
RDB快照
RDB有两种触发方式,分别是手动触发和自动触发。
无论如何触发,都是以覆盖写的形式写入到同一份RDB文件中。
手动触发
手动触发这里介绍两个命令:
save
,同步命令,也就是该命令会占用Redis的主进程,在save
命令执行期间,Redis将会阻塞所有的客户端请求,所以,当数据量非常大使,不推荐使用该命令。bgsave
,异步命令,Redis使用Linux的fork()
生成一个子进程来做持久化的工作,而主进程则继续提供其他服务。
手动触发这里只需要在配置文件中配置:
dir "/data/redis_data/6379" # 持久化文件保存的目录
dbfilename dump.rdb # 持久化文件名,可以带端口号也可以不带 dump-6379.rdb
完事重启Redis服务,就可以在线执行持久化操作了:
[root@cs 6379]# ls # 在save执行之前,还没有 rdb 文件
redis.conf redis.log
[root@cs 6379]# redis-cli -h 127.0.0.1 -p 6379 -a 1234
127.0.0.1:6379> get hello
"world"
127.0.0.1:6379> save # 持久化
OK
[root@cs 6379]# ls # 现在就有了
dump.rdb redis.conf redis.log
来个bgsave
的演示:
[root@cs 6379]# redis-cli -h 127.0.0.1 -p 6379 -a 1234
127.0.0.1:6379> bgsave
Background saving started
save
和bgsave
对比:
命令 | save | bgsave |
---|---|---|
I/O类型 | 同步 | 异步 |
是否阻塞 | 是 | 是(阻塞发生在fock()阶段,但通常非常快) |
复杂度 | O(n) | O(n) |
优点 | 不会消耗额外的内存 | 不阻塞客户端命令 |
缺点 | 阻塞客户端命令 | 需要fork子进程,消耗额外内存 |
当然了,生产中一般不会使用上述两个命令,而是使用自动触发机制。
自动触发
自动触发需要在配置文件中配置了,如下示例介绍了RDB的相关配置:
# RDB 自动持久化规则
# 当 900 秒内至少有 1 个key被改动时,自动执行持久化操作
save 900 1
# 当 300 秒内至少有 10 个key被改动时,自动执行持久化操作
save 300 10
# 当 60 秒内至少有 10000 个key被改动时,自动执行持久化操作
save 60 10000
# 数据持久化文件存储目录
dir "/data/redis_data/6379"
# RDB持久化文件名
dbfilename dump.rdb # 持久化文件名,可以带端口号也可以不带 dump-6379.rdb
# bgsave过程中发生错误时,是否停止写入,通常为 yes
rdbcompression yes
# 是否对RDB文件进行校验,通常为 yes
rdbchecksum yes
小结
RDB的优点:
- RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集。
- RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心,非常适用于灾难恢复。
- RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能。
- 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。
RDB缺点:
- 耗时、耗性能。RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求。如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度。
- 不可控、丢失数据。如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你。虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据。
使用RDB文件恢复数据
当只配置了RDB的持久化时,重启Redis服务时,会自动读取RDB文件进行数据恢复。
AOF
RDB持久化并不是完美的,如果Redis因为某些原因造成了宕机,那么将会丢失最近写入、但并未保存到快照中的数据。
在Redis1.1开始,增加了AOF来补充RDB的不足。
AOF持久化的工作机制是,每当Redis执行修改数据集的命令时,这个命令就会被追加到AOF文件的末尾。数据恢复时重放这个AOF文件即可恢复数据。说到这里,你有没有想到MySQL binlog....
我们可以在配置文件中开启AOF:
appendonly yes
appendsync always/everyesc/no
其中:
appendonly
:是(yes
)否(no
)开启AOF持久化,默认appendsync
: 触发持久化的条件,有下面三种选项:always
:每当修改数据集都会记录,慢但非常安全。everysec
:每秒钟fync一次,足够快(和使用 RDB 持久化差不多),就算有故障时也只会丢失 1 秒钟的数据。推荐(并且也是默认)使用该策略, 这种 fsync 策略可以兼顾速度和安全性。no
:由操作系统来决定什么时候同步数据。更快,也更不安全的选择,这个选项不常用。
AOF重写机制
因为AOF会一直将命令追加到文件末尾,导致该文件的体积会越来越大,而且它会保存一些重复性的命令,而这些重复性的命令可以用一条或者极少的命令就能替代....
为了优化这种情况,Redis支持:在不妨碍正常处理客户端请求中,对AOF文件进行重建(rebuild),也就是执行bgrewriteaof
命令,会生成一个新的AOF文件,这个文件包含重建当前数据集所需要的最少命令。
在Redis2.2版本之前,需要手动执行bgrewriteaof
命令,该命令会异步执行一个AOF文件重写操作,重写时会创建一个当前AOF文件的优化版本,即使bgrewriteaof
执行失败,也不会有任何数据丢失,因为旧的AOF文件在bgrewriteaof
执行成功之前不会被修改和覆盖。
到了Redis2.4则开始支持配置自动触发AOF重写机制了。
AOF重写机制的特点:减少AOF文件对磁盘的空间占用;加速数据恢复。
相关参数:
# 开启AOF持久化方式
appendonly yes
# AOF持久化文件名
appendfilename appendonly-<port>.aof
# 每秒把缓冲区的数据同步到磁盘
appendfsync everysec
# 数据持久化文件存储目录
dir "/data/redis_data/6379"
# 是否在执行重写时不同步数据到AOF文件
# 这里的 yes,就是执行重写时不同步数据到AOF文件
no-appendfsync-on-rewrite yes
# 触发AOF文件执行重写的最小尺寸
auto-aof-rewrite-min-size 64mb
# 触发AOF文件执行重写的增长率
auto-aof-rewrite-percentage 100
关于AOF重写,当AOF文件的体积大于64Mb,并且AOF文件的体积比上一次重写之久的体积大了至少一倍(100%)时,Redis将执行 bgrewriteaof 命令进行重写。
AOF的优点
- 使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync。使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据。
- AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题。
- Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。
AOF的缺点
- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
- 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。
总结
RDB和AOF对比:
选项 | RDB | AOF |
---|---|---|
数据恢复优先级 | 低 | 高 |
体积 | 小 | 大 |
恢复速度 | 快 | 慢 |
数据安全性 | 丢数据 | 根据策略决定 |
注意,这两种持久化方式可以同时使用,只不过日志量比较大而已;但生产中一般都是二选一;但在数据恢复中,优先选择AOF。
一般来说,如果想要保证足够的数据安全性,你应该同时使用两种持久化功能。
当然,AOF也是好的选择,而RDB文件则非常适合做备份,并且数据恢复也更快些。
最后,如果同时配置了RDB和AOF,那么在数据恢复时,Redis会优先选择AOF文件进行数据恢复,如果你就想使用RDB恢复怎么办?可以在配置文件中先把AOF关闭,然后重启Redis,恢复完数据,在线开启AOF即可。
持久化恢复问题
说明:
- 之前一直使用RDB进行数据持久化。
- 现在决定要使用AOF和RDB同时进行数据持久化。
现在的问题是:在开启AOF功能后,Redis在启动时会优先读取AOF文件进行数据恢复,但此时的AOF文件是空的,而数据都在RDB文件中,那启动后的Redis还是没有数据。请你尝试进行数据恢复。
解决办法参考
原因上面已经说了,AOF的优先级比RDB高,导致Redis启动时没有读取RDB文件进行恢复。
我的解决思路是:
- 将AOF持久化的所有参数都配置好,但保持配置文件中的
appendonly no
,这样做的目的让Redis认为没有开启AOF持久化,它在启动时仍会继续加载RDB文件进行数据恢复了。 - 经过上一步的动作,Redis启动后,数据恢复完毕。
- 现在要解决怎么在Redis运行时开启AOF持久化功能,我这里采用config命令执行:
config set appendonly yes
,热开启AOF持久化命令,现在AOF正常工作,根据你的AOF配置,产生了AOF文件,也将数据持久化到了该文件中。- 但有个问题,config命令是临时生效,即
appendonly yes
不会被同步到配置文件中,你还要想着去手动修改配置文件。当然,再介绍个命令:config rewrite
,将最新的配置信息重写到配置文件中,真是简单方便。
来看过程:
# 刚开始,只开启了RDB
127.0.0.1:6379> config get appendonly # AOF是关闭的
1) "appendonly"
2) "no"
127.0.0.1:6379> keys * # 有数据
1) "k1"
2) "k7"
3) "k9"
4) "k3"
5) "k2"
6) "k8"
7) "k4"
8) "k6"
9) "k10"
10) "k5"
# AOF文件也不存在
[root@cs 6379]# ls
dump.rdb redis.conf redis.log
# 配置文件:
appendonly no
appendfilename "appendonly-6379.aof"
appendfsync everysec
现在,重启Redis,让它根据RDB文件进行数据恢复:
[root@cs 6379]# redis-cli shutdown
[root@cs 6379]# redis-server redis.conf # 根据RDB文件进行数据恢复
[root@cs 6379]# redis-cli -p 6379
127.0.0.1:6379> keys * # 数据都还在
1) "k2"
2) "k9"
3) "k1"
4) "k10"
5) "k3"
6) "k8"
7) "k4"
8) "k6"
9) "k7"
10) "k5"
重要的操作来了:
127.0.0.1:6379> config get appendonly # 起初AOF还是关闭的
1) "appendonly"
2) "no"
127.0.0.1:6379> config set appendonly yes # 开启它
OK
127.0.0.1:6379> config get appendonly # AOF开启了,但配置文件的该参数还是no状态
1) "appendonly"
2) "yes"
127.0.0.1:6379> config rewrite # 将最新的配置信息重写到配置文件中
OK
此时,AOF功能开启后,AOF文件也创建好了,这个时候,你就是把RDB文件删了,数据也能从AOF中进行恢复:
[root@cs 6379]# ls
appendonly-6379.aof dump.rdb redis.conf redis.log
[root@cs 6379]# redis-cli shutdown # 关闭Redis
[root@cs 6379]# rm -rf dump.rdb # 删除RDB文件
[root@cs 6379]# vim redis.conf # 我确认了下配置文件的appenonly 的确为 yes
[root@cs 6379]# redis-server redis.conf # 启动Redis,它会根据AOF文件进行数据恢复
[root@cs 6379]# redis-cli -p 6379
127.0.0.1:6379> keys * # 数据都还在
1) "k1"
2) "k4"
3) "k3"
4) "k5"
5) "k8"
6) "k6"
7) "k10"
8) "k2"
9) "k9"
10) "k7"
127.0.0.1:6379> save # 手动save下,让它产生RDB文件
OK
[root@cs 6379]# ls # 现在两个持久化文件都有了
appendonly-6379.aof dump.rdb redis.conf redis.log
经过上面的一顿操作,数据恢复完毕,Redis再怎么重启也都有可以进行数据恢复了。
that's all,see also: