1. Redis持久化机制
Redis 支持 RDB 和 AOF 两种持久化机制,持久化功能有效地避免因进程退出造成数据丢失问题, 当下次重启时利⽤之前持久化的文件即可实现数据恢复。
2.RDB
RDB 持久化是把当前进程数据⽣成快照保存到硬盘的过程,触发 RDB 持久化过程分为手动触发和 自动触发。
2.1 触发机制
手动触发分别对应 save 和 bgsave 命令:
save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例造成长时间阻塞,基本不采用。
bgsave 命令:Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后⾃动 结束。阻塞只发生在 fork 阶段,一般时间很短。
2.2 流程说明
1) 执行bgsave命令, redis父进程判断是否有其他正在执行的子进程,如 rdb,aof。如果存在,bgsave命令直接返回。
2)父进程执行fork创建子进程,fork过程中父进程会进行阻塞,通过 info stats 命令查 latest_fork_usec 选项,可以获取最近⼀次 fork 操作的耗时,单位为微秒。
3) 父进程fork完成之后, bgsave返回"Background saving started"信息后不再阻塞父进程,可以响应其他命令。
4) 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行 lastsave命令可以获取最后一次生成RDB的时间,对应info统计的 rdb_last_save_time 选 项。
5) 进程发送信号给父进程表示完成,父进程更新统计信息
2.3 RDB文件
保存: RDB文件保存在 dir 配置指定的目录(默认 /var/lib/redis/)下,文件名通过dbfilename配置来指定(默认dump.rdb)。也可以通过config set dir {new dir} 和config set dbfilename {new filename}运行期间动态执行,下次运行时rdb文件会保存到新的目录。
压缩:Redis 默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大 小,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。
校验:如果 Redis 启动时加载到损坏的 RDB 文件会拒绝启动。这时可以使用 Redis 提供的 redischeck-dump 工具检测 RDB 文件并获取对应的错误报告。
2.4 RDB优缺点
- RDB是一个紧凑的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如六小时执行 bgsave 备份,并把 RDB 文件复制到远程机器或者文件系统中 (如 hdfs用于)灾备。
- Redis 加载 RDB 恢复数据远远快于 AOF 的方式。
- RDB 方式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运⾏都要执行 fork 创建子进程,属于重量级操作,频繁执行成本过高。
- RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有风险。
3 . AOF
AOF(Append Only File)持久化:以独立日志的方式记录每次写命令,重启时再重新执行 AOF 文件中的命令达到恢复数据的目的。AOF 的主要作用是解决了数据持久化的实时性,目前已经是 Redis 持久化的主流方式。理解掌握好 AOF 持久化机制对我们兼顾数据安全性和性能非常有帮助。
3.1 使用AOF
开启 AOF 功能需要设置配置:appendonly yes,默认不开启。AOF 文件名通过 appendfilename 配置(默认是 appendonly.aof)设置。保存目录同 RDB 持久化方式⼀致,通过 dir 配置指定。
3.2 工作流程
AOF 的工作流程操作:命令写入(append)、文件同步(sync)、文件重写 (rewrite)、重启加载(load)
1 . 所有的写入命令会追加到 aof_buf(缓冲区)中。
2. AOF 缓冲区根据对应的策略向硬盘做同步操作。
3. 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
4. 当 Redis 服务器启动时,可以加载 AOF 文件进行数据恢复。
命令写入
AOF 命令写入的内容直接是文本协议格式。例如 set hello world 这条命令,在 AOF 缓冲区会追加如下文本:
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
此处遵守 Redis 格式协议,Redis 选择文本协议可能的原因:文本协议具备较好的兼容性;实现简单; 具备可读性。
aof_buf(缓冲区)的作用: 如果每次写 AOF 文件都直 接同步硬盘,性能从内存的读写变成 IO 读写,必然会下降。先写入缓冲区可以有效减少 IO 次数,同时,Redis 还可以提供多种缓冲区同步策略,让用户根据自己的需求做出合理的平衡。
文件同步
Redis 提供了多种 AOF 缓冲区同步文件策略,由参数 appendfsync 控制不同值的含义如下表所示:
系统调用 write 和 fsync 说明:
write 操作会触发延迟写(delayed write)机制。Linux 在内核提供页缓冲区用来提供硬盘 IO 性 能。write 操作在写入系统缓冲区后立即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区 页空间写满或达到特定时间周期。同步文件之前,如果此时系统故障宕机,缓冲区内数据将丢失。
Fsync 针对单个文件操作,做强制硬盘同步,fsync 将阻塞直到数据写入到硬盘。
- 配置为 always 时,每次写入都要同步 AOF 文件,性能很差,在⼀般的 SATA 硬盘上,只能支持大约几百 TPS 写入。除非是非常重要的数据,否则不建议配置。
- 配置为 no 时,由于操作系统同步策略不可控,虽然提高了性能,但数据丢失风险大增,除非数据 重要程度很低,一般不建议配置。
- 配置为 everysec,是默认配置,也是推荐配置,兼顾了数据安全性和性能。理论上最多丢失 1 秒的 数据。
重写机制
随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入 AOF 重写机制压缩文件体积。AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF 文件。
重写后的 AOF 为什么可以变小?有如下原因:
- 进程内已超时的数据不再写入文件。
- 旧的 AOF 中的无效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版 本。
- 多条写操作合并为一条,例如 lpush list a、lpush list b、lpush list 从可以合并为 lpush list a b c。
AOF 重写过程可以手动触发和自动触发:
- 手动触发:调用bgrewriteaof 命令。
- 自动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定自动触发时 机。
- auto-aof-rewrite-min-size:表示触发重写时 AOF 的最小文件大小,默认为 64MB。auto-
- aof-rewrite-percentage:代表当前 AOF 占用大小相比较上次重写时增加的比例。
重写流程图:1. 执行 AOF 重写请求。 如果当前进程正在执行 AOF 重写,请求不执行。如果当前进程正在执行 bgsave 操作,重写命令 延迟到 bgsave 完成之后再执行。
2. 父进程执行 fork 创建子进程。
3. 重写
- 主进程 fork 之后,继续响应其他命令。所有修改操作写入AOF 缓冲区并根据 appendfsync 策 略同步到硬盘,保证旧 AOF 文件机制正确。
- 子进程只有 fork 之前的所有内存信息,父进程中需要将 fork 之后这段时间的修改操作写入 AOF 重写缓冲区中。
4. 子进程根据内存快照,将命令合并到新的 AOF 文件中。
5. 子进程完成重写
- 新文件写入后,子进程发送信号给父进程。
- 父进程把 AOF重写缓冲区内临时保存的命令追加到新 AOF 文件中。
- 用新 AOF 文件替换老 AOF文件。
宕机恢复