「Redis数据结构」字符串对象String
文章目录
- 「Redis数据结构」字符串对象String
- 一、概述
- 二、编码分类
- int
- embstr
- row
- 三、小结
- 四、参考
一、概述
字符串数据类型是Redis里最常用的类型,它的键和值都是字符串,使用起来非常的方便。虽然字符串数据类型的值都统称为字符串了,但是在实际存储时会根据值的不同自动选择合适的编码。字符串对象的编码一共有三种:int、raw、embstr。
二、编码分类
int
如果以字符串对象保存的是一个整数值,且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在ptr属性里面(void* 转为long*),并将字符串对象的编码设置为REDIS_ENCODING_INT
。
redis> SET number 10086
OK
redis> OBJECT ENCODING number
"int"
// 只对长度小于或等于 21 字节,并且可以被解释为整数的字符串进行编码
if (len <= 21 && string2l(s,len,&value)) {
if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) {
decrRefCount(o);
incrRefCount(shared.integers[value]);
return shared.integers[value]; // 这里value < REDIS_SHARED_INTEGERS,直接使用共享的字符串对象。
} else {
if (o->encoding == REDIS_ENCODING_RAW)
sdsfree(o->ptr);
o->encoding = REDIS_ENCODING_INT;
o->ptr = (void*)value;
return o;
}
}
embstr
如果字符串对象保存的是一个字符串值,并且这个字符串值长度小于等于39字节(redis3.2前)。那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值, 并将对象的编码设置为 embstr
。
redis> SET msg "hello"
OK
redis> OBJECT ENCODING msg
"embstr"
embstr
编码是专门用于保存短字符串的一种优化编码方式, 这种编码和 raw
编码一样, 都使用 redisObject
结构和 sdshdr
结构来表示字符串对象, 但 raw
编码会调用两次内存分配函数来分别创建 redisObject
结构和 sdshdr
结构, 而 embstr
编码则通过调用一次内存分配函数来分配一块连续的空间, 空间中依次包含 redisObject
和 sdshdr
两个结构。
embstr
编码将创建字符串对象所需的内存分配次数从raw
编码的两次降低为一次。- 释放
embstr
编码的字符串对象只需要调用一次内存释放函数, 而释放raw
编码的字符串对象需要调用两次内存释放函数。 - 因为
embstr
编码的字符串对象的所有数据都保存在一块连续的内存里面, 所以这种编码的字符串对象比起raw
编码的字符串对象能够更好地利用缓存带来的优势。
row
如果字符串对象保存的是一个字符串值,并且这个字符串值长度大于39(redis3.2前)字节。那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值, 并将对象的编码设置为 raw
。
redis> SET story "Long, long, long ago there lived a king ..."
OK
redis> STRLEN story
(integer) 43
redis> OBJECT ENCODING story
"raw"
三、小结
- embstr与raw都使用redisObject和sds保存数据
- embstr只分配一次内存空间,因此redisObject和sds是连续的
- raw需要分配两次内存空间,分别为redisObject和sds分配空间,不连续。
- embstr好处:创建/删除时少分配/释放一次空间,对象的所有数据连续,查找方便
- embstr坏处:当需要重新分配内存时,整个redisObject和sds都要重新分配空间,因此redis中的embstr实现为只读。
四、参考
Redis 字符串对象
《Redis 设计与实现》