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,对子进程不熟悉。
百度了下,说了子进程会复制一个父进程的内存拷贝,那么这就说得通了,因为快照肯定是不应该变更的。
后记:关于写时复制技术,概括来说就是
写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。
浙公网安备 33010602011771号