Redis RDB 文件存储实现
redis通过把内存数据保存为rdb文件来实现快照,是整个redis内核中不可缺少的一部分,为实现服务高可用提供了强有力的支撑。有以下2点作用:1. 持久化 (比 aof 恢复速度更快,也占用更小的磁盘空间,因此作为默认的持久化方式)
2. 主从同步 (开启主从后,需要首先把master上的历史数据同步到slave,这时slave就会拉取master的rdb文件,然后解析加载rdb文件到内存)
rdb 保存了真实的redis数据,相当于mysql的innodb引擎的作用,可见其重要性非同一般。rdb也可以用来离线分析redis中数据分布情况。对于如此重要的文件,其中的数据存储格式我们当然要了如指掌,这样才能运筹帷幄,让可用性达到 4个9 (99.99%), 5个9(99.999%)
到目前为止,主要的rdb 版本是 v6 v7,从redis v3.2 版本开始使用 rdb v7,之前的redis v2.8 v3.0 使用的rdb版本都是rdb v6,文件的大致格式如下:
rdb v6
- A 9 bytes magic "REDIS0006" (9字节的redis标记,其中末四位是rdb版本信息)
- key-value pairs (redis 真实的数据,以key value 成对存储)
- An EOF opcode (代表结束的标记)
- CRC64 checksum (用于对整个文件完整性校验的字符串)
rdb v7
- A 9 bytes magic "REDIS0007" (9字节的redis标记,其中末四位是rdb版本信息)
- Info field 1 (整个rdb文件中为了保存一些额外扩展信息而设计)
- Info field 2
- ...
- Info field N
- Info field end-of-fields
- key-value pairs (redis真实数据,以key value 成对存储)
- An EOF opcode (代表结束的标记)
- CRC64 checksum (用于对整个文件完整性校验的字符串)
{ "key1":"value1", "key2":"value2", "key3":"value3" }
但这里并不是这样的结构,是一个连续的按字节存储的序列。如果连续存储,其中没有其他标记,如何区分 key 与 value的边界呢?换句话也就是如何知道key这个字串哪里结束,value从哪里开始呢?redis使用了提前记录字节长度的方式实现,也就是 key-len key value-len value 这种的形式,然后按对应长度读取字符。问题又来了,redis的key的最大长度是多少呢,value的最大长度是多少呢,好像也没有明确的限制,如果你不建议性能损失的话。
redis 使用了多字节的方式保存长度(1字节、2字节、5字节、9字节 ),根据不同长度使用不同的字节,但是这里面又会出现边界问题,当从rdb文件中读取2字节,如何区分这是1字节长度值+1字节key值,还是2字节的长度值呢?到了这里似乎更加迷茫,好像陷入了一个死循环,好像无解。
如果了解UTF8编码实现原理,你一定会有可行的解决方案。是的,我们先来看看一段redis源码,因为对一个系统最好的理解就是代码+注释,更何况redis中的注释也是相当的详细,基本一看就懂。
/* The current RDB version. When the format changes in a way that is no longer * backward compatible this number gets incremented. */ #define RDB_VERSION 8 /* Defines related to the dump file format. To store 32 bits lengths for short * keys requires a lot of space, so we check the most significant 2 bits of * the first byte to interpreter the length: * * 00|XXXXXX => if the two MSB are 00 the len is the 6 bits of this byte * 01|XXXXXX XXXXXXXX => 01, the len is 14 byes, 6 bits + 8 bits of next byte * 10|000000 [32 bit integer] => A full 32 bit len in net byte order will follow * 10|000001 [64 bit integer] => A full 64 bit len in net byte order will follow * 11|OBKIND this means: specially encoded object will follow. The six bits * number specify the kind of object that follows. * See the RDB_ENC_* defines. * * Lengths up to 63 are stored using a single byte, most DB keys, and may * values, will fit inside. */ #define RDB_6BITLEN 0 #define RDB_14BITLEN 1 #define RDB_32BITLEN 0x80 #define RDB_64BITLEN 0x81 #define RDB_ENCVAL 3 #define RDB_LENERR UINT64_MAX /* When a length of a string object stored on disk has the first two bits * set, the remaining six bits specify a special encoding for the object * accordingly to the following defines: */ #define RDB_ENC_INT8 0 /* 8 bit signed integer */ #define RDB_ENC_INT16 1 /* 16 bit signed integer */ #define RDB_ENC_INT32 2 /* 32 bit signed integer */ #define RDB_ENC_LZF 3 /* string compressed with FASTLZ */
在上面的注释中有原作者的介绍,我在这里在按我自己的理解解释下:
1.
2.
3.
4.
未完待续