Redis有5种基础数据结构,分别是:string(字符串),list(链表),hash(字典),set(集合),zet(有序链表)。
string(字符串)
Redis中的字符串是一个可修改的字符串,在内存中以字节数组的形式存储,字符串也叫做 Simple Dynamic String,结构如下:
struct SDS<T> {
// 数组容量
T capacity;
// 数组长度
T len;
// 特殊标识位
byte flags;
// 数组内容
byte[] content;
}
其中,content存储的是真正的字符串内容,capacity表示所分配的数组长度,len表示字符串的长度,当数组没有冗余空间,追加内容时会分配新的数组,将旧数组中的内容拷贝出来,再append新的内容。
redis规定字符串的最大长度为512MB,创建字符串时len和capacity一样长,不分配新的冗余空间。
embstr vs raw
redis的字符串有两种存储方式,在长度特别短的时候,用emb形式存储,当长度超过44时,使用raw形式存储。这两种存储方式结构如下:
为什么长度为44?
1.先看下redis的对象头结构
struct RedisObject {
int4 type; // 4bits
int4 encoding; // 4bits
int24 lru; // 24bits
int32 refcount; // 64bits
void *ptr; // 64bits
} robj;
整个RedisObject对象头需占16个字节。
2.从文章开头我们可以看到,SDS的结构使用的是范型,当字符串比较短时,len和capacity可以使用byte和short表示,所以最小的对象头大小为content的长度+3,结构如下:
struct SDS {
// 1byte
int8 capacity;
// 1byte
int8 len;
// 1byte
int8 flags;
// 内联数组,长度为 capacity
byte[] content;
}
redis为容纳一个完整的 embstr 对象,内存分配器最少会分配 32 字节的空间,如果字符串再稍微长一点,那就是 64 字节的空间。如果总体超出了 64 字节,Redis 认为它是一个大字符串,不再使用 emdstr 形式存储,而该用 raw 形式。
存储字符串长度计算如下:
RedisObject = type(4bits)+encoding(4bits)+LRU(24bits)+refcount(64bits)+ptr(64bits);
SDS = capacity(8bits)+len(8bits)+flags(8bits)+content;
content剩余最多的长度只有45(64-19),而content中的字符串又是已 \0结尾,所有 embstr最大的字符串长度为44。
扩容策略
字符串的长度在小于1M时,扩容采用加倍策略,当长度大于1M时,为避免加倍的冗余空间过大而导致浪费,每次分配只会多1M的冗余空间。
网友评论