数据类型
String、List、Set、Zset、Hash
redisObject
使用redisObject将其他底层数据结构包装后使用
header:16B
struct redisObject {
unsigned type:4;//对象类型
unsigned encoding:4;//编码方式
unsigned lru:LRU_BITS; /* 最后一次被访问的时间,判断空闲太久的key
* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;//对象引用计数器
void *ptr;//指针,指向不同数据类型的数据,真实数据
};
数据类型对应的底层数据结构
- string:SDS
- list
linkedList:双端链表,内存占用高,内存碎片多
zipList:压缩列表,双端访问,内存占用低,存储上限低
quickList=linkedList+zipList。多个zipList,双端访问,内存占用低,存储上限高 - hash
ziplist,相邻两个节点,一个存key,一个存value
数据量大时转为dict - set
dict:key存值,value为null,内存占用大
intSet - zset:可排序set。根据score(value)排序,member(key)唯一
数据存两份,耗费内存
zskiplist + dict
typedef struct zset {
dict *dict;//唯一
zskiplist *zsl;//排序
} zset;
数据量小(128),且每个元素大小较小(64B),则使用zipList。存储时按score升序排。查找遍历
数据结构
SDS
SDS源码
大量string数据每一个都需要一个对象头,占大量空间
可以使用list等集合的形式,节约对象头的空间
sds长度小于44B,则redisObject和sds共同申请一块连续空间,少一次内存分配,效率高
大于44B,则分开申请空间,不要求连续
如果存储的字符串为整数,则直接存在ptr指针的位置(8B),无需sds
linkedlist
zipList
dict
inset
typedef struct intset {
uint32_t encoding; //编码方式 4B 16(2B) 32(3B) 64(4B)
uint32_t length; // 元素个数 4B
int8_t contents[];
} intset;
扩容
- 修改编码格式
- 计算长度,申请空间
- 倒序,将数组内容复制到新位置
- 添加新元素
- 修改header:encoding,length
skipList
- 元素升序排列。按score和ele排序
- 一个节点多个指针,不同跨度,最多32级指针。
- 便于排序查找,增删改查效率基本等于红黑树。
/* ZSETs use a specialized version of Skiplists */
typedef struct zskiplistNode {
sds ele;//值
double score;//节点分数,排序查找使用
struct zskiplistNode *backward;//前一个指针
struct zskiplistLevel {
struct zskiplistNode *forward;//下一个节点指针
unsigned long span;//索引跨度
} level[];//多级索引,最多32级
} zskiplistNode;
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;