深度了解Redis持久化的方式——RDB

目录

RDB文件的创建和载入

         设置自动间隔性保存

         服务器其他属性

          RDB文件的结构


上篇文章已经大概介绍过Redis的两种持久化方式了,现在我们去深度了解一下他们是如何工作的#

RDB文件的创建和载入

Redis的RDB持久化功能可以将Redis在内存中的数据库状态保存到磁盘中去,来避免数据的丢失。

这里主要介绍Redis服务器保存和载入RDB文件的方法,重点讲解SAVE和BGSAVE这两个命令的实现方式

  1. rdb文件的创建

SAVE命令:

       SAVE命令会阻塞Redis进程,直到rdb文件创建完毕为止,在此期间,Redis不能进行任何操作

redis>SAVE

OK

BGSAVE命令:

      BGSAVE命令不会阻塞进程,而是创建一个子进程去创建RDB文件,期间可以去进行其他操作。

 

创建RDB文件实际工作由rdb.c   or  rdbSave   函数完成,伪代码如下,可以观察上面两点的区别:

def SAVE():

      rdbSave()

def BGSAVE():

     pid = fork();   //创建子进程,pid父进程返回子进程id,子进程返回0

     if  pid == 0;   //子进程返回的0

              rdbSave()    //子进程进行RDB文件创建

              signal_parent()    //创建完成后向父进程发送信号

     elif   pid > 0:    //  父进程返回的是子进程id,都是大于0的

              handle_request_and_wait_signal()     // 父进程继续工作,等待子进程信号

     else:

             handle_fork_error()   //处理出错状态

 

      2.RDB文件的载入

 RDB文件的载入是自动载入的,当启动Redis服务器的时候会检测是否有RDB文件,有则自动载入。服务器自动载入会在日志打印   DB loaded from disk: 0.001 seconds

RDB文件载入过程中,服务器一直处于阻塞状态,直至载入完成。

rdbSave和rdbLoad之间的关系如下图

 

注意:

1》BGSAVE命令执行过程中,系统会拒绝客户端发送的SAVE命令,原因是为了避免服务器主进程和子进程同时调用rdbSave函数,防止产生竞争条件。同时两个BGSAVE也会被拒绝,因为这样也会产生竞争条件。

2》最后,BGSAVE命令和BGREWRITEAOF命令也不能同时执行。具体情况如下:

如果BGSAVE命令执行过程中收到BGREWRITEAOF命令,BGREWRITEAOF命令会被延迟到BGSAVE执行完毕后执行。如果BGREWRITEAOF命令执行过程中收到BGSAVE命令,那么BGSAVE命令会被服务器拒绝。

这种情况产生的原因:

BGREWRITEAOF和BGSAVE两个命令实际都由子进程执行,所以在命令的执行方面没有问题,但是如果并发两个子进程,并且这两个子进程都同时进行大量的磁盘写入操作,这将会占用大量资源的。

 

设置自动间隔性保存

 

上面我们提到SAVE命令会阻塞服务器,而BGSAVE不会阻塞,所以,这个任务就可以让BGSAVE来执行了。用户可以通过设置save选项来进行相关的设置,例如:

save 900 1

save 300 10

save 60  10000

意思是说,服务器在900秒、300秒、60秒之内,对数据库进行了至少1、10、10000此修改,则执行一次BGSAVE。

 

那么Redis是如何去存储这些save设置的呢?

答案就是saveparams属性。

struct redisServer{

//.....

struct saveparam *saveparams;   //记录save条件的数组。

}

对,这里的saveparams是一个数组,数组的每个元素都是一个saveparams结构

struct saveparam{

time_t seconds;    //秒数

int changes;   //改变次数

}

以上面那个保存条件为例,服务器中的数组应该是这个样子的。每个数组的成员都代表一个保存条件。

 

说到这里,那么服务器是如何实现间歇性的呢?

这里就用到了周期性操作函数serverCron,默认每100毫秒会执行一次,主要是检查是否达到了save条件,达到了就执行BGSAVE命令。

 

服务器其他属性

  • dirty计数器:记录上一次成功执行SAVE或BGSAVE后服务器对数据库操作的次数。
  • lastsave:这是一个UNIX的时间戳,记录成功执行SAVE或BGSAVE的时间。

 

struct redisSserver{

//............

long long   dirty;    //计数器

time_t   lastsave;  //上次保存的时间

//...........

}

例如:

执行

redis>SET message "hello"

OK

此时dirty计数器加1,变为 101.

 

RDB文件的结构

上面讲了那么多对RDB文件的操作,但是没有说RDB文件本身,接下来一起了解一下RDB文件的结构吧。

RDB文件就包括这五部分

1》开头的REDIS长度为5字节(是'R''E''D''I''S'五个字符,而不是字符串),在载入RDB文件时,主要通过检查开头的这五个字符来判断是否为RDB文件

2》db_version长度为4字节,是字符串表示的一个整数,这个整数代表文件的版本号。

3》databases 表示零个或者多个数据库,以及各个数据库中的键值对数据(这个部分的长度是随数据库大小而改变的,如果无数据库,则此部分也为空,长度为0字节)

4》EOF 长度1字节,标志文件正文已经读入完毕,已读入所有数据库数据。

5》check_sum 长度8字节无符号整数,这个是用来检验RDB文件是否出错的部分,通过特殊的计算每部分的情况,以此来检查文件是否出错或者损坏。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值