Redis持久化
作为一个优秀的分布式基础服务,Reids的设计很值得我们学习。本文就介绍一下Redis的持久化机制
什么是持久化
Redis的性能出色,其中一个很重要的原因是其基于内存的特性。但如果作为一个存储中间件,基于内存是万万不行的,因为万一服务器出现故障,重启以后就啥都没有了。
所以,Redis需要另外一套持久化机制将内存中的数据持久化到硬盘上,这样即使发生了不可预知的宕机事件,我们只需要将硬盘上的数据恢复到内存即可。
RDB 持久化
Redis的持久化机制一共有两种,我们先介绍第一种,就是RDB文件持久化。
RDB文件持久化就是将当前Redis数据库的状态保存成一份RDB文件,类似于一个快照的形式。然后Redis重启时直接载入RDB文件即可恢复宕机前的状态。(当然,数据可能存在不一致,因为可能会存在生成RDB尚未完成时宕机)
RDB保存命令
RDB的保存命令一共有两个,一个是SAVE、一个是BGSAVE。
两者的区别主要是前者会阻塞Redis进程,后者是fork出一个子进程进行复制。
所以,如果使用SAVE命令执行复制,客户端所有请求都会被阻塞,只有在复制完成时命令才可以被执行。而BGSAVE执行时只会影响SAVE、GBSAVE、BGREWRITEAOF三个命令,其余客户端命令则都不受影响。
RDB文件结构
一个RDB文件主要有5个部分组成:
- REDIS 这部分有5字节,就是”REDIS”字符串,方便程序快速识别是否是是RDB文件。
- db_version 4字节,RDB文件版本号。例如:”0006”就是第六版。
- database 这部分包含了一个或多个数据库,以及各个数据库的键值对信息。
- EOF 长度为1字节,标志RDB文件正式结束,当程序读到这里的时候,键值对载入结束
- check_sum 校验参数,8位无符号。用来校验前面四部分是否有文件损坏。
AOF持久化
与RDB文件快照形式不同的是,Redis还提供了一个基于增量更新的AOF持久化模式。
假设客户端执行了 SET aaa bbb
、SET bbb ccc
、SET ccc ddd
三个命令,RDB的的存储方式是将这三个键值对存放在RDB文件中,而AOF则是将这三条命令存放在AOF文件中。
AOF持久化实现
- 命令追加到aof_buf缓冲区。
Redis每次执行完一条命令以后,都会将命令添加到aof_buf缓冲区。
- 事件循环定期扫描缓冲区,如有需要则将其刷入AOF文件
刷新AOF文件的策略可以由配置项appendfsync决定,appendfsync一共有三个选项: * always 将缓冲区所有内容写入并同步到AOF文件 * everysec 将缓冲区内容写入AOF文件,如果上次同步时间距离现在超过了1s,则执行同步操作。 * no 将文件写入AOF文件,但并不执行同步,何时同步由操作系统决定。
AOF命令重写
我们来看一个很简单的例子:
SET aaa bbb
SET aaa ccc
SET aaa ddd
按照我们上面的介绍,在AOF文件里,将会存在3个命令,但事实上这3个命令操作的是同一个键,我们只需要保存最终效果即可,并不需要完整保存这3个命令。
所以Redis对于AOF机制加了一个重写的功能,通过该功能,Redis服务器可以创建一个新的AOF文件,过滤掉那些冗余的命令。
但实际上Redis的实现并不是通过分析AOF文件去重再重新生成,而是直接分析数据库当前状态,例如当前数据库的键值对是aaa ddd
,那就不需要再添加SET aaa bbb
和 SET aaa ccc
这两个命令了。
总结
RDB类似于系统快照,可以一个小时备份一次,出现宕机实践恢复比较快,而且备份过程是fork子进程处理的,不会阻塞父进程。
但是既然是快照,就不可避免会丢失一部分数据。所以,如果你的应用对丢失数据极为敏感,那么RDB不适合你。
AOF的好处是你可以根据不同的系统状态设置不一样的同步策略,尽可能的避免数据丢失。
但AOF的速度会慢于RDB,而且文件会比RDB大很多,重新加载的时间也更长。而且Redis的AOF有一些Bug,可能会导致AOF重新加载时无法恢复成保存时的原样。