本文首发于个人公众号 Java 技术大杂烩,欢迎关注
前言
平时在使用 Redis 的时候,只会使用简单的 set,get,并不明白其中的道理,为了探个究竟,搞个明白,就看了下其底层的实现 ^ ^。
Redis 的字符串是 Redis 中最基本的一种数据结构,所有的 key 都用字符串表示,且它是二进制安全的;它在内部使用一种称为动态字符串的结构来表示,可以动态的进行扩展,可以在 O(1) 的时间内获取字符串的长度等,此外,一个字符串的长度最多不能超过 512M。
常用命令字符串的一些常用命令如下:
set key value - 设置值get key -获取值append key value - 追加值decr key - 原子减1incr key - 原子加1…….动态字符串(SDS)结构定义在解析动态字符串之前,先来看看 Redis 中 Object 的定义,源码在 object.c 中,在该Object的中,定义了创建对象的一些方法,如创建字符串,创建list,创建set等,之外,还指定了对象的编码方法;接下来看下和字符串相关的方法:
指定对象的编码方式:
# object.c char *strEncoding(int encoding) { switch(encoding) { case OBJ_ENCODING_RAW: return "raw"; case OBJ_ENCODING_INT: return "int"; case OBJ_ENCODING_HT: return "hashtable"; case OBJ_ENCODING_QUICKLIST: return "quicklist"; case OBJ_ENCODING_ZIPLIST: return "ziplist"; case OBJ_ENCODING_INTSET: return "intset"; case OBJ_ENCODING_SKIPLIST: return "skiplist"; case OBJ_ENCODING_EMBSTR: return "embstr"; default: return "unknown"; } }字符串存储主要的编码方式主要有两种 : embstr 和 raw
这两种方式有什么区别呢?在什么情况下使用 embstr,在什么情况下使用 raw 呢?
当存储的字符串很短的时候,会使用 embstr 进入编码,当存储的字符串超过 44 个字符的时候,会使用 raw 进行编码;可以使用 debug object key来查看编码方式,看以下的实验:
embstr 编码的存储方式为 将 Redis Object 对象头和 SDS 对象连续存在一起,使用 malloc 方法一次分配内存,而 raw 它需要两次 malloc 分配内存,两个对象头在内存地址上一般是不连续的,它们的结构如下所示:
在 object.c 源码中看下两种字符串的创建方式:
# object.c robj *createObject(int type, void *ptr) { robj *o = zmalloc(sizeof(*o)); // 只是申请对象头的空间,会把指针指向 SDS o->type = type; o->encoding = OBJ_ENCODING_RAW; // 编码格式为 raw,为默认的编码方式 o->ptr = ptr; // 指针指向 SDS o->refcount = 1; // 可忽略 if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) { o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL; } else { o->lru = LRU_CLOCK(); } return o; } robj *createEmbeddedStringObject(const char *ptr, size_t len) { // 把对象头和SDS 连续存在一起申请内存 robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1); struct sdshdr8 *sh = (void*)(o+1); o->type = OBJ_STRING; o->encoding = OBJ_ENCODING_EMBSTR; // 为 embstr 编码方式 o->ptr = sh+1; o->refcount = 1; if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) { o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL; } else { o->lru = LRU_CLOCK(); } sh->len = len; sh->alloc = len; sh->flags = SDS_TYPE_8; if (ptr == SDS_NOINIT) sh->buf[len] = '