首页 > 技术文章 > Redis 持久化

luojiahu 2018-09-03 23:44 原文

  • 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

 

推荐阅读