Redis内存数据库的持久化机制是如何工作的?

发表时间: 2022-12-19 17:03

一、导读

Redis是内存数据库,它将字节的数据库状态存储在内存里面,所以如果不想办法将存储在内存里的数据库状态保存到磁盘中,那么Redis服务器进程一旦退出,Redis中的数据库状态也会消失不见…

总所周知,Redis实现持久化主要有两种方式——RDB和AOF,本文主要介绍RDB。

RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中,如图1:


RDB持久化所生成的RDB文件是一个经过压缩的二进制文件 ,通过该文件可以还原生成RDB文件的数据库状态,如图2:


本文主要介绍:

Redis服务器保存和载入RDB文件的方法,分析save命令和bgsave命令的实现

Redis服务器自动保存功能的实现原理

分析RDB文件的组成部分以及其结构和含义


二、RDB文件的创建与载入

Redis的save和bgsave命令用于生成RDB文件。


1.SAVE命令

save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求。

redis> SAVE //等待直到RDB文件创建完毕OK


2.BGSAVE命令

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函数完成。


3.服务器状态

接下来通过表格来说明save、bgsave和载入RDB文件时的Redis服务器状态


三、自动间隔性保存

由于bgsave命令可以在不阻塞服务器的情况下生成RDB文件,所以用户可以通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次bgsave命令。

例如:

save 900 1save 300 10save 60 10000

只要满足以下三个条件的任意一个,BGSAVE命令就会被执行:

  • 服务器在900秒之内,对数据库进行了至少1次修改
  • 服务器在300秒之内,对数据库进行了至少10次修改
  • 服务器在60 秒之内,对数据库进行了至少10000次修改


1.设置保存条件

当配置文件设置了以下值后:

save 900 1save 300 10save 60 10000

服务器状态中的保存条件的数据结构如下:


从这个数据结构可以看出,saveparams是Redis服务器的一个数组,数组中的每个元素都是一个saveparam对象,saveparam对象又有两个属性分别为seconds(秒数)和changes(修改数)


2.dirty计数器和lastsave属性

dirty计数器记录距离上一次成功执行save或bgsave命令之后,服务器对数据库状态进行了多少次修改。

lastsave属性是一个UNIX时间戳,记录了服务器上一次成功执行save或bgsave的时间。


3.检查保存条件是否满足

Redis的服务器周期性操作函数serverCron默认每隔100毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,其负责检查save选项所设置的保存条件是否已经满足,满足则执行bgsave命令。


四、RDB文件结构

这里主要讲下databases、EOF和check_sum的含义:

databases 部分包含零个或任意多个数据库,以及各个数据库中的键值对数据:

若服务器中所有数据库为空,则databases 也为空,长度为0字节

若服务器中至少有一个数据库非空,则databases 部分的长度会与数据库所保存的键值对的数量、类型和内容有关。

EOF 常量的长度为1字节,这个常量标志着RDB文件正文内容的结束,当读入程序遇到EOF时,则会感知到所有数据库的所有键值对都已经载入完毕了。


check_sum 是一个8字节的无符号整数,保存着一个校验和,其根据REDIS、db_version、databases、EOF四个部分的内容进行计算得出的。服务器在载入RDB文件时,会将载入数据所计算出的校验和与check_sum所记录的校验和进行对比,以此来检查RDB文件是否出错或损坏。


1.databases部分

一个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


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。