Redis是内存数据库,它将字节的数据库状态存储在内存里面,所以如果不想办法将存储在内存里的数据库状态保存到磁盘中,那么Redis服务器进程一旦退出,Redis中的数据库状态也会消失不见…
总所周知,Redis实现持久化主要有两种方式——RDB和AOF,本文主要介绍RDB。
RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中,如图1:
RDB持久化所生成的RDB文件是一个经过压缩的二进制文件 ,通过该文件可以还原生成RDB文件的数据库状态,如图2:
本文主要介绍:
Redis服务器保存和载入RDB文件的方法,分析save命令和bgsave命令的实现
Redis服务器自动保存功能的实现原理
分析RDB文件的组成部分以及其结构和含义
Redis的save和bgsave命令用于生成RDB文件。
save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求。
redis> SAVE //等待直到RDB文件创建完毕OK
bgsave命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求。
redis> BGSAVE //派生子进程,并由子进程创建RDB文件Background saving started
两个命令创建RDB文件的实际工作由rdb.c/rdbSave函数完成,以下是SAVE和BGSAVE的伪码
public static void save(){ rdbSave();}public static void bgSave(){ PID pid = fork();//创建子进程 if(pid == 0){ rdbSave();//子进程负责创建RDB文件 signal_parent();//完成后向父进程发送信号 }else if(pid > 0){ handle_request_and_wait_signal();//父进程继续处理命令请求,并通过轮询等待子进程的信号 }else{ handle_fork_error();//处理出错情况 }}
RDB文件会在Redis服务器启动的时候载入,但要注意是否有AOF文件。载入RDB文件是由rdb.c/rdbLoad函数完成。
接下来通过表格来说明save、bgsave和载入RDB文件时的Redis服务器状态
由于bgsave命令可以在不阻塞服务器的情况下生成RDB文件,所以用户可以通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次bgsave命令。
例如:
save 900 1save 300 10save 60 10000
只要满足以下三个条件的任意一个,BGSAVE命令就会被执行:
当配置文件设置了以下值后:
save 900 1save 300 10save 60 10000
服务器状态中的保存条件的数据结构如下:
从这个数据结构可以看出,saveparams是Redis服务器的一个数组,数组中的每个元素都是一个saveparam对象,saveparam对象又有两个属性分别为seconds(秒数)和changes(修改数)
dirty计数器记录距离上一次成功执行save或bgsave命令之后,服务器对数据库状态进行了多少次修改。
lastsave属性是一个UNIX时间戳,记录了服务器上一次成功执行save或bgsave的时间。
Redis的服务器周期性操作函数serverCron默认每隔100毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,其负责检查save选项所设置的保存条件是否已经满足,满足则执行bgsave命令。
这里主要讲下databases、EOF和check_sum的含义:
databases 部分包含零个或任意多个数据库,以及各个数据库中的键值对数据:
若服务器中所有数据库为空,则databases 也为空,长度为0字节
若服务器中至少有一个数据库非空,则databases 部分的长度会与数据库所保存的键值对的数量、类型和内容有关。
EOF 常量的长度为1字节,这个常量标志着RDB文件正文内容的结束,当读入程序遇到EOF时,则会感知到所有数据库的所有键值对都已经载入完毕了。
check_sum 是一个8字节的无符号整数,保存着一个校验和,其根据REDIS、db_version、databases、EOF四个部分的内容进行计算得出的。服务器在载入RDB文件时,会将载入数据所计算出的校验和与check_sum所记录的校验和进行对比,以此来检查RDB文件是否出错或损坏。
一个RDB文件的databases部分可以保存任意多个非空数据库。
此RDB文件保存了0号和6号数据库中的所有键值对数据
REDIS | db_version | database 0 | database 6 | EOF | check_sum |
而每个非空数据库在RDB文件中都保存以下三个部分
SELECTDB | db_number | key_value_pairs |
SELECTDB 常量的长度为1字节,当程序读到这个值时,它知道接下来要读入的将是一个数据库号码。
db_number 保存着一个数据库号码,长度为1、2或5字节,当程序读入db_number部分后,服务器会调用select命令,根据读入的数据库号码进行数据库切换,使得之后读入的键值对可以载入到正确的数据库中。
key_value_pairs部分保存数据库的所有键值对。若键值对带有过期时间,则过期时间也会和键值对保存在一起。
例如:0号数据库中的结构:
SELECTDB | 0 | key_value_pairs |
对应于本节开始给出的RDB文件,补充完整如下图:
REDIS | db_version | SELECTDB | 0 | pairs0 | SELECTDB | 6 | paris6 | EOF | check_sum |
点击查看原文,获取更多福利!
https://developer.aliyun.com/article/1113950?utm_content=g_1000366218
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。