Redis数据状态: 保存在Redis数据库中的数据被称作数据状态。
RDB文件的创建与载入
有两个Redis命令可以用于生成RDB文件, 一个是SAVE
, 另一个是BGSAVE
RDB文件创建
-
SAVE
命令会阻塞Redis
服务器进程, 知道RDB文件创建完毕为止, 在服务器进程阻塞期间, 服务器不能处理任何命令请求. -
BGSAVE
派生出一个子进程, 然后由子进程创建RDB, 服务器进程继续处理命令请求.
RDB文件载入
RDB文件的载入工作时在服务器启动时自动执行的, 所以redis并没有专门用于载入rdb文件的命令, 只要redis服务器在启动时检测到rdb文件存在, 它就会自动载入RDB文件.
-
如果服务器开启了AOF持久化功能, 那么服务器会优先使用AOF文件来还原数据库状态
-
只有在AOF持久化功能处于关闭状态时, 服务器才会使用RDB文件来还原数据库状态。
SAVE, BGSAVE, BGREWRITEAOF
-
在BGSAVE命令执行期间, 客户端发送的
SAVE
命令会被服务器拒绝, 服务器禁止SAVE命令和BGSAVE
命令同时执行时为了避免父进程和子进程同时执行两个rdbSave
调用, 防止产生竞争条件 -
在
BGSAVE
命令执行期间, 客户端发送的BGSAVE
命令会被服务器拒绝, 因为同时执行两个BGSAVE
命令也会产生竞争条件. -
BGREWRITEAOF
和BGSAVE
两个命令不能同时执行:-
如果
BGSAVE
命令正在执行, 那么客户端发送的BGREWRITEAOF
命令会被延迟到BGSAVE
命令执行完毕之后执行 -
如果
BGREWRITEAOF
命令正在执行, 那么客户端发送的BGSAVE
命令会被服务器拒绝。
-
RDB文件载入时的服务器状态
服务器在载入RDB文件期间, 会一直处于阻塞状态, 直到载入工作完成为止.
自动间隔性保存
redis允许用户通过设置服务器配置的save
选项, 让服务器每隔一段时间自动执行一次BGSAVE
.
-
save 900 1
-
save 300 10
-
save 60 10000
只要满足以下三个条件中的任意一个, BGSAVE
命令就会被执行
-
服务器在900秒之内, 对数据进行了一次修改
-
服务器在300秒之内, 对数据库进行了至少10次修改
-
服务器在60秒之内, 对数据库进行了至少10000次修改。
设置保存条件
redis主要通过save
设置选项, 默认的配置选项如上所示: 接着, 服务器程序会根据save选项所设置的保存条件, 社会服务器状态redisServer
结构的saveparams
属性:
struct redisServer { // 记录了保存条件的数据 struct saveparam *saveparams; }
其中saveparams
属性时一个数组, 数据中的每个元素都是一个saveparam结构, 每个saveparam结构都保存了一个save选项设置的保存条件:
struct saveparam {
// 秒数
time_t seconds;
// 修改数
int changes;
}
dirty计数器和lastsave属性
除了saveparams
数组之外, 服务器状态还维持着一个dirty计数器, 以及一个lastsave属性:
-
dirty
计数器记录距离上一次成功执行SAVE
命令或者BGSAVE
命令之后, 服务器对数据库状态进行了多少次修改(包括写入, 删除, 更新等操作) -
lastsave
属性是一个UNIX时间戳, 记录了服务器上一次成功执行SAVE命令或者BGSAVE命令的时间.
检查保存条件是否满足
-
遍历保存的所有的保存条件
-
计算从上次成功执行
BGSAVE
和save
到现在所经历的秒数 -
当
BGSAVE
命令执行完成之后, 则lastsave
设置为当前时间, 并将dirty
清零
RDB文件结构
RDB文件结构, 整体包含了五部分:
-
REDIS
-
db_version
-
databases
-
EOF
-
check_sum
REDIS
RDB文件最开头是REDIS部分, 这部分的长度为5字节, 保存着”REDIS”五个字符串, 程序在加载的时候, 能够快速检查所在如的文件是否RDB文件.
db_version
db_version长度为4字节, 他的值是一个字符串表示的整数, 这个整数记录了RDB
文件的版本号. 例如: 0006
代表RDB文件版本为第六版
databases
databases部分包含着零个或任意多个数据库, 以及各个数据库中的键值对数据:
-
如果服务器的数据库状态为空, 那么这个部分也为空, 长度为0字节
-
如果服务器的数据库状态为非空, 那么这部分也为非空, 根据数据库保存键值对的数量, 类型和内容不同, 这部分的长度也会有所不同。
EOF
常量长度为1字节, 这个常量标志着RDB文件正文内容的结束, 当读入程序遇到这个值的时候, 它知道所有数据库的所有键值对已经载入完毕。
check_sum
check_sum
是一个8字节长的无符号整数, 保存着一个校验和, 这个校验和是程序通过对REDIS
,db_version
,databases
,EOF
四个部分的内容进行计算得出的。
分析RDB文件
对于RDB文件的分析, 我们可以使用od
命令行来分析
-
-c
可以以ascii编码的方式打印输入文件 -
-x
参数可以以十六进制的方式打印输入文件
不包含任何键值对的RDB文件
redis> FLUSHALL redis> SAVE od -c dump.rdb 0000000 R E D I S 0 0 0 6 377 334 263 C 360 Z 334 0000020 362 V 0000022
根据之前学习的RDB文件结构知识, 当一个RDB文件没有包含任何数据库数据时, 这个RDB文件将由一下四个部分组成:
-
五个字节的”REDIS”
-
五个字节的版本号(db_version)
-
一个字节的EOF常量
-
八个字节的检验和(check_sum)
从上面例子中, 0006
版本号之后, 一个字节377
代表EOF
常量, 然后334 263 C 360 Z 334 362 V
八个字节则达标RDB文件的校验和.
包含字符串键的RDB文件
redis> FLUSHALL redis> SET msg "HELLO" $ od -c dump.rdb 0000000 R E D I S 0 0 0 6 376 \0 \0 003 m s g 0000020 005 H E L L O 377 \n < 342 005 < A 217 4 0000037
一个数据库被保存到RDB文件时, 这个数据库将由以下三个部分组成:
-
一个一字节长的特殊值
SELECTDB
-
一个长度可能为
一字节
,两字节
,五字节
的数据库号码(db_number) -
一个或以上数量的键值对(key_value_pairs)
通过上面的输出:
-
376
代表SELECTDB
常量 -
之后的
\0
代表整数0, 表示被保存的数据库为0号数据库 -
直到
377
为止, RDB文件包含有\0 003 m s g 005 H E L L O
-
没有过期时间的键值对由
类型(TYPE)
,键(key)
,值(value)
三部分组成-
其中类型的长度为一字节
-
建和值都是字符串对象, 并且字符串在未被压缩前, 都是义字符串长度为前缀, 后跟字符串内容本身的方式来存储的。
-
-
\0
就是字符串类型的TYPE
值REDIS_RDB_TYPE_STRING
-
003
是键MSG
的长度值 -
005
则是HELLO
的长度
-
包含带有过期时间的字符串键的RDB文件
redis> FLUSHALL redis> SETEX msg 10086 "HELLO" redis> SAVE $ od -c dump.rdb 0000000 R E D I S 0 0 0 6 376 \0 374 m e 254 035 l 001 \0 \0 \0 003 m s g 005 H E L L O 377 005 ' 234 214 _ 245 254 350 '
一个带有过期时间的键值对将由以下部分组成:
-
一个一字节长的
EXPIRETIME_MS
特殊值 -
一个八字节长的过期时间(ms)
-
一个一字节长的类型(TYPE)
-
一个键key和一个值(value)
根据这些特征, 可以得出RDB文件各个部分的意义:
-
REDIS 0006
: RDB文件标志和版本号 -
376 \0
: 切换到0号数据库 -
374
: 代表特殊值EXPIRETIME_MS
-
m e 254 035 l 001 \0 \0
代表八字节长的过期时间 -
\0 003 m s g
:\0
表示这是一个字符串键, 003是键的长度, MSG是键 -
005 H E L L O
: 005是值的长度,HELLO
是值 -
377
: 代表EOF常量 -
005 ' 234 214 _ 245 254 350
: 代表八字节长的检验和
包含一个集合键的RDB文件
redis> FLUSHALL redis> SADD LANG "C" "JAVA" "RUBY" redis> SAVE $ od -c dump.rdb R E D I S 0 0 0 6 376 \0 002 004 l a n g 003 004 R U B Y 004 J A V A 001 c 377 224 363 E 7 363 \t j {
-
REDIS006: RDB文件标志和版本号
-
376 \0: 切换到0号数据库
-
002 004 l a n g:
-
002 是常量
REDIS_RDB_TYPE_SET
(这个常量实际值为整数2), 表示这是一个哈希表编码的集合键 -
004 表示键的长度
-
LANG: 键的名称
-
-
003:集合的大小
-
004 R U B Y: 集合的第一个元素
-
004 J A V A: 集合的第二个元素
-
001 C: 集合的第三个元素
-
377: 代表常量EOF
-
: 代表校验和
关于分析RDB文件的说明
因为REDIS本身带有RDB文件检查工具