Redis 持久化介绍(RDB 和 AOF)
RDB 方式简介
RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时 Redis 会自动将内存中的所有数据生成一份副本并存储在硬盘上,这个过程即为“快照”。redis会在以下几种情况下对数据进行快照:
- 根据配置规则进行自动快照
- 用户执行 save 或 bgsave 命令
- 执行 flushall 命令
- 执行复制 (replication) 时
根据配置规则进行自动快照
redis 允许用户在配置文件中自定义快照条件,预置条件及含义如下:
1 | save 900 1 # 表示 900 秒内有一个或一个以上的键被更改,则进行快照。 |
用户执行 save 或 bgsave 命令
除了自动快照外,当进行服务重启、手动迁移以及备份时,也会需要手动执行快照操作。redis 提供了两个命令来完成手动快照操作。
(1) save 命令
当执行 save 命令时,redis 同步的进行快照操作,在快照执行的过程中会阻塞所有客户端请求。当数据较多时,会导致redis较长时间不能响应,要避免在生产环境使用 save 命令。
(2) bgsave 命令
bgsave 命令可以在后台异步的进行快照操作,快照的同时服务器还可以仅需响应来自客户端的请求。如果想知道快照是否完成,可以使用 lastsave 命令获取最近一次成功执行快照的时间。(执行自动快照时,redis 采用的策略是异步快照)
执行 flushall 命令
当 redis 配置文件中有定义快照条件时,执行 flushall 命令时,才会进行快照。
执行复制时
当设置了主从模式时,redis 会在复制初始化时进行自动快照,即使没有定义自动快照条件,也没有手动执行快照操作。
快照原理
执行过程
- Redis 使用 fork 函数复制一份当前进程(父进程)的副本(子进程);
- 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
- 当子进程写入完所有数据后会用该临时文件替换掉旧的 RDB 文件,至此一次快照操作完成。
从操作系统的角度看 redis 快照
在执行 fork 的时候操作系统(类 Unix 操作系统)会使用写时复制(copy-on-write)策略,即 fork 函数发生的一刻父子进程共享一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的 RDB 文件存储的是执行 fork 一刻的内存数据。
写时复制策略也保证了在 fork 的时刻虽然看上去生成了两份内存副本,但实际上内存的占用量并不会增加一倍。这就意味着当系统内存只有 2GB,而 Redis 数据库的内存只有 1.5GB 时,执行 fork 后内存使用量并不会增加到 3GB (超出物理内存)。为此需要确保 Linux 系统允许应用程序申请超过可用内存(物理内存和交换分区)的空间,方法是在 /etc/sysctl.conf 文件加入 vm.overcommit_memory = 1,然后重启系统或者执行 sysctl_vm.overcommit_memory=1确保设置生效。
另外需要注意的是,当进行快照的过程中,如果写入操作较多,造成 fork 前后数据差异较大,是会使得内存使用量显著超过实际数据大小的,因为内存中不仅保存了当前的redis 数据库的数据,而且还保存着 fork 时刻的内存数据。进行内存用量估算时很容易忽略这一问题,造成内存用量超限。
RDB 小结
Redis 在进行快照的过程中不会修改 RDB 文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候 RDB 文件都是完整的。这使得我们可以通过定时备份 RDB 文件来实现 Redis 数据库备份。RDB 文件是经过压缩(可以配置 rdbcompression)参数以禁用压缩节省 CPU 占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。
通过 RDB 方式实现持久化,一旦 Redis 异常退出,就会丢失最后一次快照以后更改的所有数据。为了应对这种情况,可以通过组合设置快照条件降低数据损失的数量,也可以使用 AOF 方式进行持久化。
AOF 方式简介
AOF 可以将 Redis 执行的每一条写命令追加到硬盘文件中,这种持久化方式会一定程度降低 Redis 性能。
开启 AOF
默认情况下 redis 没有开启 AOF(append only file) 方式的持久化,可以通过 appendonly 参数启用:
1 | appendonly yes |
开启 AOF 持久化后每执行一条会非读的操作命令,都会被 redis 写入到硬盘中的 AOF 文件。AOF 文件的保存位置和 RDB 文件的位置相同,默认文件名为 appendonly.aof
AOF 文件优化
AOF 文件的内容是 Redis 客户端向 Redis 发送的原始通信协议的内容,所以如果对同一个数据进行多次修改,就是在 AOF 文件中记录多次,但我们想要的仅是最后一次修改后的数据,所以最好可以将无用的记录删除掉。redis 支持用户设置这样的条件,当达到条件的时候,就会自动重写 AOF 文件,这个条件可以在配置文件中设置:
1 | auto-aof-rewrite-percentage 100 |
还可以使用 bgrewriteaof 命令手动执行 AOF 文件重写。重写过程只与内存中的数据有关,aof文件中的已有内容无关。
AOF rewrite 过程:
- redis fork一个子进程
- 子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志
- redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件
- 子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中
- 用新的日志文件替换掉旧的日志文件
同步硬盘数据
虽然每次执行更改数据的操作 redis 都会将命令记录在 AOF 文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正的写入硬盘,而是进入了系统的硬盘缓存。 在默认情况下系统每 30 秒会执行一次同步操作,以便将硬盘缓存中的内容真正的写入硬盘,在这 30 秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。可以通过配置 appendfsync 参数设置同步:
1 | # appendfsync always |
- everysec 每秒执行一次同步操作(默认)
- always 每次执行修改数据的操作都会执行同步(最安全最慢的方式)
- no 表示不主动同步,即由操作系统来做(30秒一次,不可控)
AOF 破损文件修复
如果redis在append数据到AOF文件时,机器宕机了,可能会导致AOF文件破损,用 redis-check-aof --fix
命令可以修复破损的AOF文件
RDB 和 AOF 的优缺点
RDB 的优缺点
优点
- RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备
- RDB对redis对外提供的读写服务影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
- 相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速
缺点
- redis故障时,会丢失数据.一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据
- RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒
AOF 的优缺点
优点
AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据
AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。
AOF日志文件的命令通过可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据
缺点
对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
AOF开启后,支持的写QPS会比RDB支持的写QPS低
数据恢复的时候,会比较慢,还有做冷备,定期的备份,不太方便,可能要自己手写复杂的脚本去做,做冷备不太合适
总结
配置合理的 RDB 持久化方式最快,适用于对数据丢失在一定范围内可以容忍的缓存应用。AOF 持久化方式更安全,但可以较高程度的保证系统异常不会对数据造成破坏,但需要付出性能的代价。redis 也支持同时使用 RDB 和 AOF 的方式持久化,在重启后恢复数据的时候,会选择 AOF 文件进行恢复。
冷备策略
每小时做一次备份
编写脚本 redis_rdb_copy_hourly.sh
1 | #!/bin/sh |
添加脚本到定时任务:
1 | crontab -e |
每天做一次备份
编写脚本 redis_rdb_copy_daily.sh
1 | #!/bin/sh |
添加脚本到定时任务:
1 | crontab -e |
数据恢复方案
- 如果是 redis 进程挂掉,那么重启 redis 进程即可,直接基于AOF日志文件恢复数据, 最多就丢一秒的数
- 如果是 redis 进程所在机器挂掉,那么重启机器后,尝试重启 redis 进程,尝试直接基于AOF日志文件进行数据恢复,如果AOF文件破损,那么用
redis-check-aof fix
- 如果 redis 当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复
文章标题:Redis 持久化介绍(RDB 和 AOF)
文章字数:3.3k
本文作者:Waterandair
发布时间:2017-11-07, 23:38:23
最后更新:2019-12-28, 14:03:59
原始链接:https://waterandair.github.io/2017-11-07-redis-persistence.html版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。