Redis持久化之RDB

一 RDB文件的创建

  想要创建RDB有两个命令,BGSAVE和SAVE。

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

  BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续处理命令请求。

  在执行BGSAVE命令期间,不会再接受SAVE,BGSAVE和BGREWRITEAOF命令

二 周期性执行保存RDB文件

  Redis提供了周期性保存RDB的功能,Redis配置文件里由如下的配置

   save  900  1
   save  300  10
  save  60    10000

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

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

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

  这么做的原理如下

  

 

  

 

 

   同时服务器对象里还有两个成员变量,dirty计数器和lastsave时间戳

  

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

  

 

  

三 RDB文件的结构

  

 

  REDIS是固定字符,5个字节。

  db_version长度4个字节,表示版本号。比如Redis 2.8版本 rdb文件版本号就是 "0006"。

  EOF和校验和没啥好说的

  

 

  

 

  

   这里的TYPE只是value的TYPE,因为key固定是字符串

 

文本参考自 https://zhuanlan.zhihu.com/p/72238519 和 https://zhidao.baidu.com/question/630007539131193364.html

为什么 Redis 使用子进程而不是线程来进行后台 RDB 持久化呢?主要是出于Redis性能的考虑,我们知道Redis对客户端响应请求的工作模型是单进程和单线程的,如果在主进程内启动一个线程,这样会造成对数据的竞争条件。所以为了避免使用锁降低性能,Redis选择启动新的子进程,独立拥有一份父进程的内存拷贝,以此为基础执行RDB持久化。

但是需要注意的是,fork 会消耗一定时间,并且父子进程所占据的内存是相同的,当 Redis 键值较大时,fork 的时间会很长,这段时间内 Redis 是无法响应其他命令的。除此之外,Redis 占据的内存空间会翻倍。

 

1、父子进程之间的关系
关于资源:子进程得到的是除了代码段是与父进程共享的以外,其他所有资源的都是得到父进程的一个副本,子进程的所有资源都继承父进程,得到父进程资源的副本,既然为副本,也就是说,二者并不共享地址空间。,两个是单独的进程,继承了以后二者就没有什么关联了,子进程单独运行。(采用写时复制技术)
关于文件描述符:继承父进程的文件描述符时,相当于调用了dup函数,父子进程共享文件表项,即共同操作同一个文件,一个进程修改了文件,另一个进程也知道此文件被修改了。
2、线程与进程之间的关系
一个进程的线程之间共享由进程获得的资源,但线程拥有属于自己的一小部分资源,就是栈空间,保存其运行状态和局部自动变量的。堆是堆,栈是栈。栈可以叫做:堆栈,栈,栈和堆栈指的都是stack,只是叫法不一样。而堆就只能叫做堆。在线程中new出来的空间占的是进程的资源,也就是说是占用的堆资源(heap)。

 

看Redis的RDB的时候有一丝疑惑,就是它是怎么做快照的。因为Redis设计与实现书里并没有详细说。网络上很多说法都是子进程,由于自己并不熟悉linux,对子进程不熟悉。

百度了下,说了子进程会复制一个父进程的内存拷贝,那么这就说得通了,因为快照肯定是不应该变更的。

 

后记:关于写时复制技术,概括来说就是 

  写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。

posted on 2021-07-20 10:14  MaXianZhe  阅读(327)  评论(0)    收藏  举报

导航