①. git源码地址:git clone https://github.com/redis/redis.git (redis-6.0.8\redis-6.0.8\src)
②. Redis基本的数据结构(骨架)
①. 总结语:redis是key-value存储系统,其中key类型一般为字符串, value类型则为redis对象(redisObject)
②. 6大类型说明(粗分)
④. C语言struct结构体语法简介
⑤. 字典、KV是什么:每个键值对都会有一个dictEntry
⑥. redisObject +Redis数据类型+Redis 所有编码方式(底层实现)三者之间的关系
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> type hello
string
127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> debug object hello
Value at:0x7fa41f80e3a0 refcount:1 encoding:embstr serializedlength:6 lru:891806 lru_seconds_idle:61
127.0.0.1:6379>
struct redisObject {/*对象的类型,包括:OBJECT_STRING、OBJECT_LIST、OBJECT_HASH、OBJECT_SET、OBJECT_ZSET */unsigned type:4;/*具体的数据结构*/ unsigned encoding:4;/*24位,对象最后一次被命令程序访问的时间,与内存回收有关*/unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or* LFU data (least significant 8 bits frequency* and most significant 16 bits access time). *//*引用计数,当refcount=0的时候,表示该对象已经不被任何对象引用,则可以进行垃圾回收了*/int refcount;/*指向对象实际的数据结构*/void *ptr;
};
②. embstr:代表embstr格式的SDS(Simple Dynamic String 简单动态字符串),保存长度小于44字节的字符串。EMBSTR顾名思义即:embedded string,表示嵌入式的String
③. raw:保存长度大于44字节的字符串
①. C语言中字符串展示
②. Redis没有直接复用C语言的字符串,而是新建了属于自己的结构-----SDS
在Redis数据库里,包含字符串值的键值对都是由SDS实现的(Redis中所有的键都是由字符串对象实现的即底层是由SDS实现,Redis中所有的值对象中包含的字符串对象底层也是由SDS实现)
③. Redis为什么重新设计一个SDS数据结构?
谈谈自己对内存重新分配理解:比如现在有一个set key1 value1 使用的是sds8进行存储,这个时候重新set key1 value(没有超过1个bite),那么就会继续延用以前的,如果大于了1个bite,那么就会重新分配比如分配到sds16
④. len:记录buf数组中已使用字节数量
flags:当前类型(不同的sdshdr)
alloc:不包括头和空结束符的字节数量
typedef **char** *sds;
struct __attribute__ ((__packed__)) sdshdr5 {unsigned char flags; /* 3 lsb of type, and 5 msb of string length */char buf[];};struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /* used */uint8_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];};struct __attribute__ ((__packed__)) sdshdr16 {uint16_t len; /* used */uint16_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];};struct __attribute__ ((__packed__)) sdshdr32 {uint32_t len; /* used */uint32_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];};struct __attribute__ ((__packed__)) sdshdr64 {
static inline char sdsReqType(size_t string_size) {if (string_size < 32) return SDS_TYPE_5;if (string_size < 0xff) //2^8 -1 return SDS_TYPE_8;if (string_size < 0xffff) // 2^16 -1 return SDS_TYPE_16;if (string_size < 0xffffffff) // 2^32 -1 return SDS_TYPE_32;return SDS_TYPE_64;
}
①. 我们先来瞅一瞅三大编码长什么样?
②. 当字符串键值的内容可以用一个64位有符号整形来表示时,Redis会将键值转化为long型来进行存储,此时即对应 OBJ_ENCODING_INT 编码类型。内部的内存结构表示如下:
命令示例: set k1 123
③. Redis启动时会预先建立10000个分别存储0 - 9999的redisObject变量作为共享对象,这就意味着如果set字符串的键值在0~10000之间的话,则可以直接指向共享对象而不需要再建立新对象,此时键值不占空间
set k1 123
set k2 123
①. 先来瞅一瞅源码
②. 当字符串的键值为长度大于44的超长字符串时,Redis则会将键值的内部编码方式改为OBJ_ENCODING_RAW格式,这与OBJ_ENCODING_EMBSTR编码方式的不同之处在于,此时动态字符串sds的内存与其依赖的redisObject的内存不再连续了
③. 明明没有超过阈值,为什么变成raw了
④. 只有整数才会使用int,如果是浮点数, Redis内部其实先将浮点数转化为字符串值,然后再保存
⑤. embstr与raw类型底层的数据结构其实都是SDS(简单动态字符串,Redis内部定义sdshdr一种结构)