Redis持久化之RDB持久化
看CyC2018的Redis部分时候,不明白两种持久化是什么怎么做的。
今天看到了《Redis设计与实现》,直接先从持久化看。
1 总览
什么是持久化?
Redis是一个内存型数据库,其数据库状态储存在内存中,一旦服务器进程退出,服务器中的数据库状态也会消失。所以我们需要把储存在内存中的数据库状态保存到磁盘里面,避免数据意外丢失。
2 RDB持久化
RDB持久化
这个功能可以将Redis在内存中的 数据库状态 保存在磁盘里面,避免数据意外丢失。
两种方式
- RDB持久化既可以手动执行;
- 也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中。
RDB文件
RDB持久化功能生成的RDB文件是一个经过 压缩 的** 二进制文件**,通过该文件可以 还原 生成RDB文件时的数据库状态。
可以看出RDB文件应该是采用的无损压缩方式。
所谓无损压缩格式,是利用数据的统计冗余进行压缩,可完全恢复原始数据而不引起任何失真,但压缩率是受到数据统计冗余度的理论限制,一般为2:1到5:1.这类方法广泛用于文本数据,程序和特殊应用场合的图像数据(如指纹图像,医学图像等)的压缩。
RDB文件保存在硬盘里面,所以即使Redis服务器进程退出,甚至宕机,只要RDB文件存在,Redis服务器就可以用它还原数据库状态。
2.1 RDB文件的创建与载入
1 两个Redis命令用于生成RDB文件
- SAVE:SAVE会 阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求。
- BGSAVE:BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续处理命令请求。
创建RDB文件的工作由rdb.c/rdbSave函数完成,SAVE命令和BGSAVE命令会以不同方式调用这个函数,伪码如下:
def SAVE():
# 创建RDB文件
rdbSave()
def BGSAVE():
# 创建子进程
pid = fork()
if pid == 0:
# 子进程负责创建RDB文件
rdbSave()
# 完成之后向父进程发送信号
signal)parent()
elif pid > 0:
# 父进程继续处理命令请求,并通过轮询等待子进程的信号
bandle_request_and_wait_signal()
else:
# 处理出错情况
handle_fork_error()
fork()函数以前学操作系统的时候遇到过:
一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。
fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;
在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。