Redis作为一个缓存为保证宕机时不丢失数据和尽快恢复也有自身的持久化机制。
1、RDB
保存当前数据库的快照
手动触发
SAVE:主进程执行快照保存,在保存时会阻塞其他命令
BGSAVE:主进程派生一个子进程创建RDB文件,主进程继续处理请求,使用写时复制机制
自动触发
使用save命令进行自动保存条件的配置,例如:
save 900 1 # 900秒(15分钟)内如果发生1次写操作,则保存快照
save 300 10 # 300秒(5分钟)内如果发生10次写操作,则保存快照
save 60 10000 # 60秒内如果发生10000次写操作,则保存快照
接着服务器程序会根据save选项所设置的保存条件,设置服务器状态redisServer结构的saveparams属性。saveparams属性是一个数组,数组中的每个元素都是一个saveparams结构都保存了一个save选项所设置的保存条件。
struct saveparams{
// 秒数
time_t seconds;
// 修改参数
int changes;
};
除了saveparams数组之外,服务器状态还维护着一个dirty计数器,以及一个lastsave属性。
dirty计数器记录距离上一次成功执行SAVE命令或者BGSAVE命令之后,服务器对数据库状态(服务器中的所有数据库)进行了多少次修改(包括写入、删除、更新等操作)
lastsave属性是一个UNIX时间戳,记录了服务器上一次成功执行SAVE命令或者BGSAVE命令的时间。
当服务器成功执行一个数据库修改命令之后,程序就会对dirty计数器进行更新:命令修改了多少次数据库,dirty计数器的值就设置为多少。
Redis的ServerCron默认每100毫秒执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查save选项所设置的保存条件是否已经满足,如果满足的话,就执行BGSAVE命令
程序会遍历并检查saveparams数组中的所有保存条件,只要有任意一个条件被满足,那么服务器就会执行BFSAVE命令。
2、AOF
RDB持久化保存数据库状态的方法是将各个键值对的二进制文件保存到RDB文件中,而AOF持久化保存数据库状态的方法是将服务器执行的SET、SADD等执行的具体命令保存到AOF文件中
过程为以下两步:
- 命令追加:当服务器执行完一个写命令后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区末尾
- 文件写入:服务器将aof_buf缓冲区中的内容写入和保存到AOF文件里面,可以通过配置appendfsync属性决定写入时机
| 值 | 行为 |
|---|---|
| always | 立即将缓冲区中的所有内容同步到AOF文件 |
| everysec | 每隔一秒将缓冲区中的内容同步到AOF文件 |
| no | 何时同步由操作系统进行决定 |
AOF重写
AOF通过保存被执行的写命令来记录数据库状态,所以随着服务器运行时间的流逝,AOF文件中的内容会越来越多,文件的体积也会越来越大。
AOF文件重写并不需要对现有AOF文件进行任何读取、分析和写入操作。是通过读取服务器当前的数据库状态来实现的。首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是AOF文件重写的原理。
后台AOF重写期间,会创建一个子进程进行重写操作和一个AOF重写缓冲区,主进程继续执行任务。
主进程将写命令追击到AOF缓冲区和AOF重写缓冲区。
AOF缓冲区的内容会定期被写入和同步到AOF文件,对现有AOF文件的处理正常进行
从创建子进程开始,服务器执行的所有命令都会被记录到AOF重写缓冲区中。
子进程完成AOF重写工作之后,会向父进程发送一个信号,父进程在接收到该信号后会将AOF重写缓冲区中的所有内容写入到新AOF文件中,并替换旧的AOF文件
3、RDB+AOF
也可以共同使用RDB和AOF进行持久化,在RDB持久化期间,AOF记录新来的写入指令,保证数据尽量不丢失。恢复时先读取RDB文件尽快恢复,然后读取AOF补齐数据。
参考文献:《redis设计与实现》