Redis的持久化机制
RDB持久化
RDB持久化既可以手动,也可以配置,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中。
RDB文件是一个经过压缩的二进制文件,通过文件可以还原生成RDB文件时的数据库状态。
RDB文件的创建与载入
有2个命令可以生成RDB文件:SAVE和BGSAVE。SAVE命令会阻塞主进程,BGSAVE会派生子进程,由子进程创建
RDB文件。
redis> SAVE
OK
redis> BGSAVE
Background saving started
RDB文件的载入是在服务器启动时自动执行的,检测到RDB文件就会自动载入RDB文件。但是AOF文件的更新频率
通常比RDB文件的更新频率高,所以:开启了AOF,会优先使用AOF。
BGSAVE命令执行时的服务器状态
因为BGSAVE命令的保存工作是由子进程执行的,所以在子进程创建RDB文件的过程中,Redis服务器可以继续处
理客户端的命令请求。BGSAVE命令执行期间,服务器处理SAVE、BGSAVE、BGREWRITEAOF和平时不同。
- BGSAVE执行期间,客户端发送的SAVE命令会被拒绝,因为同时执行父进程和子进程都会调用rdbSave,产生竞
争。两个BGSAVE命令也同理。
-
BGSAVE和BGREWRITEAOF不能同时执行:
- 如果BGSAVE正在执行,客户端发送的BGREWRITEAOF会延迟到BGSAVE之后执行。
- 如果BGREWRITEAOF正在执行,那么客户端发送的BGSAVE会被服务器拒绝。
因为BGREWRITEAOF和BGSAVE都是由子进程执行,并且同时执行大量IO操作,不是好策略。
RDB文件载入时的服务器状态
服务器在载入RDB文件期间,会一直阻塞到完成。
自动间隔性保存
Redis允许用户通过设置save,让服务器每隔一段时间自动执行一次BGSAVE命令。
可以设置多个保存条件,只要任意条件被满足,服务器就会执行BGSAVE命令。
save 900 1 // 900s内至少1次修改就执行BGSAVE命令
save 300 10 // 300s内至少10次修改
save 60 10000 //
检查保存条件是否满足
周期性操作函数serverCron默认每隔100毫秒会执行一次,检查save是否满足条件,满足就执行BGSAVE。
RDB文件结构
-
RDB开头是五个字符“REDIS”,快速检查载入文件是否为RDB文件。
-
db_version是RDB文件的版本号。
-
databases包含零个或多个数据库。
-
EOF表示正文内容结束。
-
check_sum保存校验和,通过前四个字段计算得出,检查RDB文件是否有出错的情况出现。
例子:
redis> set MSG "HELLO"
redis> save
$ od -c dump.rdb
R E D I S 0 0 0 6 376 \0 \0 003 M S G 005 H E L L O 377 207 z = 304 f T L 343
// 377代表EOF
AOF持久化
AOF通过保存Redis执行的写命令来记录数据库状态。Redis的命令请求协议是纯文本格式,所以AOF文件是纯文本。
AOF持久化的实现
命令追加
AOF打开后,服务器执行一个写命令后,会将写命令追加到aof_buf缓冲区末尾。
AOF文件的写入与同步
Redis的进程是一个事件循环,这个循环中的文件事件负责接收客户端的命令请求,以及发送回复,而时间事件则执行定时运行的函数。
服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到aof_buf缓冲区里面,所以在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里。flushAppendOnlyFile函数的行为由appendfsync来配置。
通过配置appendfsync可以决定缓冲区的内容什么时候放入AOF文件里,
- 设置为always,每次write后都会调用fsync(Linux为调用fdatasync)。
- 设置为everysec为最多每秒调用一次fsync,这种模式性能并不是很糟糕,因为所有fsync操作都异步交给了BIO线程。
- 设置为no,write后不会有fsync调用,由操作系统自动调度刷磁盘,性能是最好的。
AOF文件的载入与数据还原
- 创建一个不带网的fake client。
- 从AOF文件中读取一条写命令。
- 直到读完。
AOF重写
随着时间流逝,AOF会越来越大,
记录这个list键的状态,AOF就要保存六条命令。
AOF文件重写的实现
如果服务器想尽量少的命令记录list键的状态,简单高效的方法就是!读取list的值,太聪明了!我宣布个事,六条
命令减少到了一条。
因为aof_rewrite函数生成的新AOF文件只包含还原当前数据库状态所必须的命令,所以新AOF文件不会浪费任何
硬盘空间。
AOF后台重写
aof_rewrite使用子进程解决主进程阻塞的问题,可是,如果新的命令可能会对数据库进行修改,从而造成当前状
态和重写后的AOF文件保存的数据库状态不一致。
为了解决这个问题,Redis服务器设置了一个AOF重写缓冲区,当Redis执行了写命令之后,会同时发给AOF缓冲区
和AOF重写缓冲区(在服务器创建子进程之后开始使用)。
这就是AOF后台重写!也即是BGREWRITEAOF命令。
Reference
《Redis设计与实现》