Redis是内存数据库,需要将存储在内存中的数据库状态保存到磁盘里,避免数据丢失。持久化即把数据保存到可永久存储的设备中。
一、RDB持久化机制
RDB文件是数据库 某个状态经过压缩后的二进制文件,通过该文件还原到数据库当初的状态。默认情况下,Redis的RDB文件名为dump.rdb。
1.RDB文件的创建和载入
(1)通过save和bgsave命令创建RDB文件
- save命令会阻塞Redis服务器进程,知道RDB文件创建完毕,阻塞期间不可以处理任何请求指令。(不消耗内存但阻塞)
- bgsave命令会派生出一个子进程fork,让子进程去创建RDB文件,相当于子进程执行save命令,自己(父进程)继续执行请求指令。在bgsave期间,父进程会拒绝save和bgsave指令,防止产生竞争条件;对于BGREWRITEAOF指令也会延迟到bgsave后执行,该指令虽然是由子进程执行,没有冲突,但从性能方面考虑,不能同时执行。(消耗内存但不阻塞)
(2)服务器启动时自动载入RDB文件
2.自动间隔性保存
在redis.window.conf配置文件中,有这么三行代码
save 900 1 save 300 10 save 60 10000
服务器在900s内,对数据库进行了至少1次修改
服务器在300s内,对数据库进行了至少10次修改
服务器在60s内,对数据库进行了至少10000次修改
只要满足任意一个条件,bgsave命令就会自动执行.
服务器状态的结构体 包含了 保存条件结构体,可以自行设置保存条件
//服务状态
struct redisServer{ //.. struct saveparam* saveparam;//记录保存条件的数组 //.. };
//保存条件 struct saveparam{ time_t seconds;//秒数 int changes;//修改数 };
服务器状态还有2个属性来判断是否执行保存
//服务器状态 struct redisServer{ //.. struct saveparam* saveparam;//记录保存条件的数组 long long dirty;//修改计数器,记录上一次修改后,数据库改了多少次 time_t lastsave;//上一次执行保存的时间戳 //.. };
3.RDB文件结构
- REDIS部分的长度为5字节,保存"REDIS"五个字符,通过这五个字符快速检查所载入的文件是不是RDB文件,这里不是C字符串"REDIS "。
- db_version长度为4字节,它的值是一个字符串表示的整数,例如"0006"就代表RDB文件的版本为第六版。
- databases部分包含零个或任意多个数据库,以及各个数据库中的键值对数据。如果服务器的数据库状态为空,则database为空;状态不为空也根据数据库所保存的键值对信息而长度不同。
- EOF(End of File)表示读入程序读到文件尾,占1字节。
- check_sum是一个8字节长的无符号整数,保存一个校验和,这个校验和是程序通过前四个部分计算得出的。载入文件时会将载入数据所计算出的结果和原本记录的check_sum进行对比,以此来检查RDB文件是否有误。
databases部分可以保存任意多个非空数据库
- SELECTDB常量的长度为1字节,当读入时就知道下一个是数据库号码。
- db_number保存着一个数据库号码,长度可以是1、2、5字节。读到这个东西会调用select命令,根据读入的号码切换。
- key_value_pairs部分保存了数据库中所有键值对信息,过期的键没删除的话也在里面,每个键值对信息如下,如果不带过期时间则没有前面两个信息。根据TYPE类型来选择保存的value对象类型。
二、AOF持久化机制
AOF全称是Append Only File,通过保存Redis服务器所执行的写命令来记录数据库状态。是日志文件,通过执行命令还原数据库状态。被写入AOF文件的所有命令都是以Redis命令请求协议格式(纯文本)保存的,
1.AOF持久化的实现
- 命令追加:服务器执行完一个写命令之后会把该命令追加到aof_buf缓冲区的末尾
- 写入与同步:redis服务器进程是一个事件循环,负责接收客户端的命令请求并回复。时间事件负责执行像serverCron函数这样需要定时运行的函数。服务器每次结束一个事件循环之前,都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里
很显然,always效率最慢,安全性最高,即使出现故障最多也只是丢失一个事件循环中的命令数据;第二个折中;第三个写入AOF文件很快,不同步会导致数据累积,下一次同步时耗时最长。
2.AOF文件的载入和数据还原
服务器只要读入并重新执行一遍AOF文件里的命令就可以还原数据库状态
3.AOF重写
如果堆积很多命令造成文件庞大,不如保留键最后的值,将若干条命令替换成一条(设置键值)。
4.AOF后台重写
为了防止阻塞,服务器将AOF重写交给子进程进行,父进程继续执行客户端请求的命令。在AOF重写期间执行其他写命令的话会使得重写后的AOF文件不能还原到最新状态。因此在AOF重写期间,父进程将此期间执行的写命令,除了追加进AOF缓冲区,顺便追加进AOF重写缓冲区,待重写完成,把AOF重写缓冲区的内容追加到新的AOF文件,这就保证了状态一致。
三、对比分析
还是老样子,有利必有弊,一般都是结合使用。
参考&引用
《redis设计与实现》