第 10 章:RDB 持久化¶
Redis 服务器数据库示例。
![digraph {
rankdir = LR;
node [shape = record];
label = "\n图 10-1 数据库状态示例";
subgraph cluster_server {
label = "Redis 服务器";
db0 [label = "数据库 0 | { k1 | v1} | { k2 | v2 } | { k3 | v3 }"];
db1 [label = "数据库 1 | { k1 | v1} | { k2 | v2 } | { k3 | v3 }"];
db2 [label = "数据库 2 | { k1 | v1} | { k2 | v2 } | { k3 | v3 }"];
db0->db1 -> db2 [style = invis];
}
}](_images/graphviz-a4e917364ed50ce5371932bbc89cdb583808d1e8.png)
Redis 保存和载入 RDB 文件的流程。
![digraph {
rankdir = LR;
label = "\n图 10-2 将数据库状态保存为 RDB 文件";
//
state [label = "数据库状态", shape = circle];
rdb [label = "RDB 文件", shape = note, height = 1.8, width = 1.4];
//
state -> rdb [label = "保存为", minlen = 2.5];
}](_images/graphviz-01b40ce008a46cb6b4448c1c9627148fd951903c.png)
![digraph {
rankdir = LR;
label = "\n图 10-3 用 RDB 文件来还原数据库状态";
//
state [label = "数据库状态", shape = circle];
rdb [label = "RDB 文件", shape = note, height = 1.8, width = 1.4];
//
state -> rdb [dir = back, label = "还原", minlen = 2.5];
}](_images/graphviz-d4c074422658a2c071dff78b44eaadc3954f855c.png)
RDB 文件的创建与载入¶
服务器判断是载入 RDB 文件还是载入 AOF 文件的流程。
![digraph {
label = "\n图 10-4 服务器载入文件时的判断流程";
node [shape = box];
//
server_star [label = "服务器启动", width = 3]
start_load [label = "执行载入程序", width = 3];
aof_or_not [label = "已开启 AOF 持久化功能?", shape = diamond];
load_by_aof [label = "载入 AOF 文件"];
load_by_rdb [label = "载入 RDB 文件"];
//
server_star -> start_load -> aof_or_not;
aof_or_not -> load_by_aof [label = "是"];
aof_or_not -> load_by_rdb [label = "否"];
}](_images/graphviz-4ddd2cbff384c68e915d11f1d661f7f3c4cb71f6.png)
负责创建和载入 RDB 文件的两个函数之间的关系。
![digraph {
label = "\n图 10-5 创建和载入 RDB 文件";
rankdir = LR;
splines = polyline
//
node [shape = circle, width = 1.3, height = 1.3];
state [label = "数据库状态"];
rdb [label = "RDB 文件"];
//
edge [minlen = 2.5];
state -> rdb [label = "rdbSave"];
rdb -> state [label = "\nrdbLoad"];
}](_images/graphviz-d54f61c5fdfb9b89955ff9580279376db1b815c4.png)
自动间隔性保存¶
记录了服务器触发自动 BGSAVE
条件的 saveparams
属性。
![digraph {
label = "\n图 10-6 服务器状态中的保存条件";
rankdir = LR;
node [shape = record];
//
redisServer [label = " redisServer | ... | <saveparams> saveparams | ... "];
saveparams [label = " { { saveparams[0] | seconds \n 900 | changes \n 1 } | { saveparams[1] | seconds \n 300 | changes \n 10 } | { saveparams[2] | seconds \n 60 | changes \n 10000 } } "];
//
redisServer:saveparams -> saveparams;
}](_images/graphviz-80c9daa03c7660ab83c919e82543ae45289c0e46.png)
记录服务器最后一次执行 SAVE
或者 BGSAVE
的时间,
以及自最后一次保存 RDB 文件以来,
服务器进行了多少次写入的 lastsave
属性和 dirty
属性。
![digraph {
label = "\n图 10-7 服务器状态示例";
rankdir = LR;
node [shape = record];
//
redisServer [label = " redisServer | ... | dirty \n 123 | lastsave \n 1378270800 | ... "];
}](_images/graphviz-30c073b3d2c334b3a091a68ac38660903d686562.png)
用于记录和检查服务器是否需要自动执行 BGSAVE
的相关属性和数据结构的示例。
![digraph {
label = "\n图 10-8 服务器状态";
rankdir = LR;
node [shape = record];
//
redisServer [label = " redisServer | ... | <saveparams> saveparams | ... | dirty \n 123 | lastsave \n 1378270800 | ... "];
saveparams [label = " { { saveparams[0] | seconds \n 900 | changes \n 1 } | { saveparams[1] | seconds \n 300 | changes \n 10 } | { saveparams[2] | seconds \n 60 | changes \n 10000 } } "];
//
redisServer:saveparams -> saveparams;
}](_images/graphviz-d86de7a06d4dd613f9296fb210b3de50c280111d.png)
RDB 文件结构¶
RDB 文件的总体结构。
![digraph {
label = "\n图 10-10 RDB 文件结构";
node [shape = record];
rdb [label = " REDIS | db_version | databases | EOF | check_sum "];
}](_images/graphviz-b0b05fb491bff29077e3cf7afca171fc7777de7a.png)
包含数据库 0
和数据库 3
的非空 RDB 文件结构示例。
![digraph {
label = "\n图 10-12 带有两个非空数据库的 RDB 文件示例";
node [shape = record];
rdb [label = " REDIS | db_version | database 0 | database 3 | EOF | check_sum "];
}](_images/graphviz-6167454f7fc816385336badc2f2f40f60f672b59.png)
RDB 文件中的数据库结构。
![digraph {
label = "\n图 10-13 RDB 文件中的数据库结构";
node [shape = record];
database [label = " SELECTDB | db_number | key_value_pairs "];
}](_images/graphviz-ed7f323651c08db48eb84cb21e4a609d0777e121.png)
示例。
![digraph {
label = "\n图 10-14 数据库结构示例";
node [shape = record];
value [label = " SELECTDB | 0 | key_value_pairs "];
}](_images/graphviz-7a6a182172da4d89b37b87a79dc5ee0629835cd3.png)
包含了数据库部分的 RDB 文件示例。
![digraph {
label = "\n图 10-15 RDB 文件中的数据库结构示例";
node [shape = record];
v [label = " REDIS | db_version | SELECTDB | 0 | pairs | SELECTDB | 3 | pairs | EOF | check_sum"];
}](_images/graphviz-8781ea50d083982e677dfa11b5a5616dfd43062a.png)
不带过期时间的键值对结构。
![digraph {
label = "\n图 10-16 不带过期时间的键值对";
node [shape = record];
kvp [label = " TYPE | key | value "];
}](_images/graphviz-e2077e76096c95111bdb16207691c0ef8286fd4c.png)
示例。
![digraph {
label = "\n图 10-18 无过期时间的字符串键值对示例";
node [shape = record];
string [label = " REDIS_RDB_TYPE_STRING | key | value "];
}](_images/graphviz-3c63a4fee2854410e3a7b9868464c11ae2336b7d.png)
带有过期时间的键值对结构。
![digraph {
label = "\n图 10-17 带有过期时间的键值对";
node [shape = record];
kvp [label = " EXPIRETIME_MS | ms | TYPE | key | value "];
}](_images/graphviz-23af1c5c65bc0be2a8d6ca776761bf10657561c0.png)
示例。
![digraph {
label = "\n图 10-19 带有过期时间的集合键值对示例";
node [shape = record];
set [label = " EXPIRETIME_MS | 1388556000000 | REDIS_RDB_TYPE_SET | key | value "];
}](_images/graphviz-0a7e151e9bea0c5a9116e23c3c7e459454f97487.png)
int
编码的字符串对象的结构。
![digraph {
label = "\n图 10-20 INT 编码字符串对象的保存结构";
node [shape = record];
v [label = " ENCODING | integer "];
}](_images/graphviz-19d580c80819754c049e281a6db88d718ef79e99.png)
示例。
![digraph {
label = "\n图 10-21 用 8 位来保存整数的例子";
node [shape = record];
v [label = " REDIS_RDB_ENC_INT8 | 123 "];
}](_images/graphviz-4c704cbc6f44bfe9b568046346ccb883b92f02c7.png)
内容没有被压缩的字符串对象的结构。
![digraph {
label = "\n图 10-22 无压缩字符串的保存结构";
node [shape = record];
value [ label = " len | string "];
}](_images/graphviz-ca0f26c7219d4909bfd1294ffe94ed3b8fe3db5e.png)
示例。
![digraph {
label = "\n图 10-24 无压缩的字符串";
node [shape = record];
value [ label = " 5 | \"hello\" "];
}](_images/graphviz-5fe2bc45ef8f520c84911d42e4aceb65f866bd06.png)
内容被压缩后的字符串对象的结构。
![digraph {
label = "\n图 10-23 压缩后字符串的保存结构";
node [shape = record];
value [ label = " REDIS_RDB_ENC_LZF | compressed_len | origin_len | compressed_string "];
}](_images/graphviz-5ead17df0f656b7613888915e7581812f920ccb6.png)
示例,
其中 ?
代表的是无法用字符串形式打印出来的字节。
![digraph {
label = "\n图 10-25 压缩后的字符串";
node [shape = record];
value [label = " REDIS_RDB_ENC_LZF | 6 | 21 | \"?aa???\" "];
}](_images/graphviz-573c7ebf1108e889a71f329468101de83e133804.png)
列表对象的结构。
![digraph {
label = "\n图 10-26 LINKEDLIST 编码列表对象的保存结构";
node [shape = record];
value [label = " list_length | item1 | item2 | ... | itemN "];
}](_images/graphviz-9d0e7023cd8db57d2f6a738f3fd79b47f0cefc2a.png)
示例。
![digraph {
label = "\n图 10-27 保存 LINKEDLIST 编码列表的例子";
node [shape = record];
list [label = " 3 | 5 | \"hello\" | 5 | \"world\" | 1 | \"!\" "];
}](_images/graphviz-ca3b86f3598b08b1abc3717d51ca1f41c6fb9d39.png)
集合对象的结构。
![digraph {
label = "\n图 10-28 HT 编码集合对象的保存结构";
node [shape = record];
value [ label = " set_size | elem1 | elem2 | ... | elemN "];
}](_images/graphviz-082f7a6cf09da27831bfdb1ade08a7848e7dc2a1.png)
示例。
![digraph {
label = "\n图 10-29 保存 HT 编码集合的例子";
node [shape = record];
set [label = " 4 | 5 | \"apple\" | 6 | \"banana\" | 3 | \"cat\" | 3 | \"dog\" "];
}](_images/graphviz-930c31eacceb5d9ec9d3c2159ce53c34001a8a22.png)
哈希对象的结构。
![digraph {
label = "\n图 10-30 HT 编码哈希表对象的保存结构";
node [shape = record];
hash [label = " hash_size | key_value_pair 1 | key_value_pair 2 | ... | key_value_pair N "];
}](_images/graphviz-de7fe9ee29f695d288fd155dd67bb8c9e1843e75.png)
更详细的哈希对象结构。
![digraph {
label = "\n图 10-32 更详细的 HT 编码哈希表对象的保存结构";
node [shape = record];
hash [label = " hash_size | key1 | value1 | key2 | value2 | ... | keyN | valueN "];
}](_images/graphviz-3a540e4e1c1e7c432f50d6f550b5c774b42971c3.png)
示例。
![digraph {
label = "\n图 10-33 保存 HT 编码哈希表的例子";
node [shape = record];
hash [label = " 2 | 1 | \"a\" | 5 | \"apple\" | 1 | \"b\" | 6 | \"banana\" "];
}](_images/graphviz-51febc3fda032098d2561b4ce97428f0e07860e7.png)
有序集合对象结构。
![digraph {
label = "\n图 10-34 SKIPLIST 编码有序集合对象的保存结构";
node [shape = record];
zset [label = " sorted_set_size | element1 | element2 | ... | elementN "];
}](_images/graphviz-fa61e364cddd3d2eeaefc359bd1e1a44284ba065.png)
更详细的有序集合对象结构。
![digraph {
label = "\n图 10-36 更详细的 SKIPLIST 编码有序集合对象的保存结构";
node [shape = record];
sorted_set [label = " sorted_set_size | member1 | score1 | member2 | score2 | ... | memberN | scoreN "];
}](_images/graphviz-5eb036c9f983021b9fff410b9b1128548b3e2ce2.png)
示例。
![digraph {
label = "\n图 10-37 保存 SKIPLIST 编码有序集合的例子";
node [shape = record];
sorted_set [label = " 2 | 2 | \"pi\" | 4 | \"3.14\" | 1 | \"e\" | 3 | \"2.7\" "];
}](_images/graphviz-1a79c7674770894dbfc58cd0d2528e8c485c308d.png)