Redis 持久化
参考文章深入学习Redis,写的真不错,相当深入,但本篇相对浅薄。
持久化: Redis 是内存数据库,数据存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将 Redis 中的数据从内存保存到硬盘中;下次 Redis 重启后,通过持久化文件实现数据的恢复。
Redis 持久化分为两种方式,一种是 RDB(Redis DataBase)持久化,一种是 AOF(Append Only File)方式。前者将数据快照到硬盘,后者将每次执行的写命令以追加的方式保存到文件。
RDB 持久化
RDB持久化是将当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据。
触发条件
- 手动触发
save 命令和 bgsave 命令都可以生成 RDB 文件。
save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求。
而bgsave命令会创建一个子进程,由子进程来负责创建RDB文件,父进程(即Redis主进程)则继续处理请求。
save 命令执行时,会阻塞整个服务器,在服务器阻塞期间,不能再处理其他请求;bgsave 只会在 fork 子线程的时候阻塞服务器。
- 自动触发
从 Redis 配置文件中可以看到,通过配置 save seconds changes 来指定 RDB 的触发条件。
该配置的含义是:xx 秒后,如果至少有 xx 个数据发生改变,则执行 RDB 快照。
RDB 快照保存在 Redis 根目录下的 dump.rdb 文件中。
AOF 持久化
AOF持久化(即Append Only File持久化),是将Redis执行的每次写命令记录到单独的日志文件中(有点像MySQL的binlog);当Redis重启时再次执行AOF文件中的命令来恢复数据。
与RDB相比,AOF的实时性更好。
Redis 默认开启 RDB 持久化方式,可以通过配置开启 AOF 持久化。
默认为 appendonly no ,将其改为 yes
另外注意这张图片最上面那句话,翻译过来是:可以同时启用 AOF 和 RDB 持久化,没有问题。如果在启动时启用了 AOF,Redis 将加载 AOF,即具有更好持久性保证的文件。
由于需要记录 Redis 的每条写命令,因此 AOF 不需要被触发,有以下三个流程
- 命令追加 append
- 文件写入 write 和文件同步 sync
- 文件重写 rewrite
命令追加
Redis 先将命令追加到缓冲区 aof_buf,不是直接写入文件;避免每次写命令都要写入文件,IO 过于频繁。
文件写入和文件同步
为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。
AOF缓存区的同步文件策略由参数appendfsync控制,三个参数:
- always:命令写入 aof_buf 后立即调用系统 fsync 操作同步到AOF文件,fsync 完成后线程返回。这种情况下,每次有写命令都要同步到 AOF 文件,硬盘 IO 成为性能瓶颈。
- no:命令写入 aof_buf 后调用系统write操作,不对 AOF 文件做 fsync 同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。
- everysec:命令写入 aof_buf 后调用系统write操作,write完成后线程返回;fsync 同步文件操作由专门的线程每秒调用一次。everysec 是前述两种策略的折中,是性能和数据安全性的平衡,因此是 Redis 的默认配置。
文件重写
随着时间流逝,Redis 服务器执行的写命令越来越多,AOF 文件也会越来越大;过大的 AOF 文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长。
文件重写可以压缩 AOF 文件,其原因如下:
- 过期数据不再写入 AOF 文件
- 无效命令不再写入 AOF 文件,如有些数据被重复设值(set mykey v1, set mykey v2)、有些数据被删除了(sadd myset v1, del myset)
- 多条命令可以合并为一个:如 sadd myset v1, sadd myset v2, sadd myset v3 可以合并为 sadd myset v1 v2 v3
文件重写触发条件
- 手动触发
直接调用 bgrewriteaof 命令,该命令的执行与 bgsave 有些类似:都是 fork 子进程进行具体的工作,且都只有在 fork 时阻塞。
redis-cli
127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started
redis-sever
[18280] 14 Jul 09:45:04.157 * Background append only file rewriting started by pid 14220
[18280] 14 Jul 09:45:04.563 * AOF rewrite child asks to stop sending diffs.
[18280] 14 Jul 09:45:04.673 # fork operation complete
[18280] 14 Jul 09:45:04.685 * Background AOF rewrite terminated with success
[18280] 14 Jul 09:45:04.686 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
[18280] 14 Jul 09:45:04.692 * Background AOF rewrite finished successfully
- 自动触发
由配置参数 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 决定
- auto-aof-rewrite-min-size:执行AOF重写时,文件的最小体积,默认值为64MB。
- auto-aof-rewrite-percentage:执行AOF重写时,当前AOF大小(即aof_current_size)和上一次重写时AOF大小(aof_base_size)的比值。
两种方式优缺点
RDB
优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。
缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的 Redis 不兼容新版本的RDB文件)。
AOF
与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。