对RDB实现持久化的过程进行剖析
持久化概述
持久化
因为Redis数据库是基于内存的Key-Value型数据库,他的所有数据库状态都存储在内存里面,如果服务器进程退出,那么存放在内存中的所有Redis数据库的状态都将消失。为了避免这种情况发生,就需要一种将数据库状态从内存转移到磁盘中的技术。
持久化就是这样一种将数据库的状态从内存存储到磁盘中的技术,Redis提供两种持久化:RDB持久化和AOF持久化。
RDB持久化
Redis提供了RDB持久化功能,这个功能可以将 Redis在内存中的数据库状态保存到磁盘里面,避免数据意外丢失。RDB持久化功能所生成的RDB文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态。
RDB命令
Redis中生成RDB文件有两个命令:SAVE和BGSAVE。
SAVE命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求;BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求
由此可见BGSAVE的实现是在SAVE的基础上进行的。
RDB文件的载入工作是在服务器启动时自动执行的,所以Redis并没有专门用于载入RDB文件的命令,只要 Redis服务器在启动时检测到RDB文件存在,它就会自动载入RDB文件。
生成RDB文件实现
在讲生成RDB文件前首先要讲一个Redis中对I/O进行封装的一个结构体:rio
,这个结构体在基本I/O的基础上加了一些计算校验和,获取文件指针所在偏移量等功能。
1 | struct _rio { |
SAVE的实现就是依靠rio
的,其所有的I/O都是通过rio
进行的。SAVE实现
1 | int rdbSave(char *filename) { |
从代码逻辑上看,SAVE的实现还是比较简单的,首先写入一些Redis版本信息,然后将数据库中的所有数据写入文件,最后加上一个校验和。
BESAVE在SAVE的基础上还要实现一些新进程创建等任务
1 | int rdbSaveBackground(char *filename) { |
RDB文件载入实现:
1 | int rdbLoad(char *filename) { |
RDB文件结构
从SAVE命令的实现过程,我们能够知道一个RDB文件总体结构可以这样划分:
在数据库数据部分其最基本的元素是键值对,存储在RDB的数据又可以分含有过期键的键值对和没有过期键的键值对两种
没有过期键的键值对组织形式:
含有过期键的键值对组织形式: