- Overall Insight:
Redis 提供两种持久化方式:
a. RDB 方式的内存快照,支持以指定的时间间隔和操作数定义内存快照的记录间隔。
b. AOF(Append Only File),以命令日志方式记录的每次请求Redis的命令记录,记录方式为追加方式(Append Only)。Redis 还支持在AOF文件过大时对其进行重写。
c. 两种持久化方式均可独立配置打开或者关闭。当同时开启时,在Redis重启时优先选取AOF文件作为恢复文件,因为其相比RDB记录了更加完整的数据。
- RDB
- 配置:
save N(seconds) M(operations)
表示当在N秒内最少进行了M次写入操作,则进行RDB持久化;
可以配置多项,满足任何一项配置都将进行RDB持久化;
可以通过SAVE/BGSAVE命令手动触发;
- 优点:
a. 以非常紧凑的形式组织的即时内存快照。适合于备份数据,可以结合crontab等形式进行数据备份。
b. 相比AOF保证Redis在打开持久化时有最佳的性能保证,RDB的生成通过fork子进程的方式进行,子进程负责完成文件的写入,主服务进程不参与磁盘读写。
c. 在Redis重启恢复是,RDB文件有更高的效率。通常速率数倍于同等数据下的AOF文件。
- 缺点:
a. 可能导致一段时间内的数据丢失,例如:配置SAVE 3 100,如果在上次记录RDB后Redis down掉,则近3s内的近百条写入记录可能将全部丢失。
b. RDB需要fork子进程进行持久化操作,当Redis占用内存较大时,fork操作本身可能比较耗时,这将可能导致主服务进程进入数毫秒至数秒的阻塞,影响及时响应客户端。AOF 的重写操作(?)也需要fork 子进程完成,该参数可以配置,而对持久化本身没有影响(反观RDB,可能因为这种情况的存在,需要配置RDB的时间间隔尽量大)。
- 如何进行:
进行RDB持久化,拢共分三步:
第一步:fork一个子进程
第二步:子进程将数据写入临时RDB文件
第三步:子进程写入完成,替换老的RDB文件
This method allows Redis to benefit from copy-on-write semantics.
这里强调这种方式得益于写时复制(CoW)技术,在linux中,CoW是指在fork子进程时,不会将父进程的数据全部复制,而仅仅将子进程的数据引用指向父进程的数据地址,只有当父进程中有对相应数据的修改动作时,才为子进程分配数据空间
- AOF
通过追加写的方式记录Redis的每次写入操作到AOF文件中。
- 配置:
appendonly yes
当打开AOF配置后,每次写操作命令都会被记录到AOF文件尾。当重启时,Redis会加载此文件来恢复数据。
- AOF文件的磁盘持久化策略:
Redis支持对AOF的磁盘持久化进行配置,以获取不同程度的数据安全性和性能保证。支持三种策略:
always
every second
no
三种方式表示调用fsync系统函数的频率,always表示每次写操作命令被记录后都会调用fsync进行磁盘同步,最大程度保证数据的持久性,但是由于同步磁盘耗时较大,会导致性能变慢。every second 表示每秒进行磁盘同步,是对数据安全性和速度的折衷方案。no 表示 Redis不主动调用fsync函数实现磁盘同步,而依赖系统机制实现,这个时间在Linux下通常会是20-30秒,因此仍旧有较大的数据丢失可能。
- 优点:
a. AOF提供更好的持久性保证,可以配置不同的fsync策略: always, every sec, no 三选一。默认的 every sec 保证了最大时间间隔为1s的数据丢失(事实上最坏情况下将是2s).
b. AOF 文件为写追加方式,因此在诸如断电等系统down机的情况下,文件也不会损坏,及时遇到写到一半的文件,也可以通过工具轻松恢复。另外,即时误敲了如flushall 一类的命令,只要AOF未进行重写,则还可以通过AOF文件恢复数据。
c. 当AOF文件过大时,Redis可以自动对其进行重写,并且保证AOF文件的安全性(因为重写是通过新建文件写入的)。
d. AOF 文件便于理解,可读性强,可以自己编写程序解析。
- 缺点:
a. 同样的数据,AOF比RDB大。
b. 根据fsync配置的不同,AOF通常会导致Redis响应更慢(虽然在这里,Redis官方文档还在强调,在every sec配置下,此时Redis性能仍非常好(still very high))。
- AOF 的重写(Rewrite)
由于AOF记录了每次写操作命令,可以预见,随着时间的递进,可能有很多历史的写操作变得无效。例如对一个String类型反复执行set操作,最后一个set操作才决定该key –value 对的最终状态,而其之前的操作都变得无关紧要。因此随着时间增长,AOF文件会变得越来越大,但是其中一部分的内容没有实际意义。
对于这种情况,Redis支持AOF文件的重写,其操作步骤如下:
a. fork 出子进程
b. 子进程在临时文件中进行AOF重写
c. 父进程同时保持两个动作:1)继续对所有的写请求,向原AOF文件写入,保证数据的安全性 2)将所有新来的写请求记录到一块单独的内存缓冲区中。
d. 当子进程完成重写后,父进程收到通知,将内存缓冲区中的新的变化追加到临时文件中
e. 将两个文件进行交换重命名,并向启用新的AOF文件。
- 如何选择?
很明显,两种持久化方式的选择需要在数据安全性和速度间做权衡。Redis 官方文档建议:
1. 如果可以忍受分钟级的数据写入丢失,则可以只开启RDB
2. 有很多人仅仅开启了AOF,但官方不建议这么做,因为:a) RDB适合数据备份 b) 可以通过RDB迅速恢复
官方还给出:最终Redis的愿景是将RDB和AOF统一,但这是一项“长期计划”。
- 两种持久化方式都开启的情况
在2.4版本以上,Redis保证在进行RDB的同时不会进行AOF重写,避免子进程同时进行大量的磁盘IO。即使用户通过BGREWRITEAOF命令显式要求AOF重新,若此时正在进行RDB,Redis将返回OK状态,在RDB进行完毕后再进行AOF重写。
同时开启的情况下,Redis重启时,优先加载AOF文件来重放数据。
- 关于持久化的建议
1. 确保你的数据库经过备份
2. 备份的数据应该带上时间戳信息,时间区间信息,以方便区分
3. 至少每天一次,将你的数据库从Redis运行的物理机备份至其他地方(SCP)
4. 监控你的备份
[References]
1. https://redis.io/topics/persistence
2. http://oldblog.antirez.com/post/redis-persistence-demystified.html