Redis有6种基本数据结构:
- 简单动态字符串(SDS)
- 双向链表(linkedlist/quicklist)
- 哈希表 (hash)
- 跳表(skiplist)(重点关注,面试常问)
- 整数列表(intset)
- 压缩列表(ziplist)
- radix-tree (Stream会用到)
一、简单动态字符串(SDS)
1、数据结构
Redis中所有键的类型都是SDS,值可能是不同类型,当然常见的值类型是SDS。
(图片来源:极客时间Redis专栏)
如:RPUSH zoo "dog" "panda" "cat"
Key: zoo 是 字符串对象类型,value :dog、panda、cat都是字符串对象类型。
SDS结构定义和数据结构如下:
- free:分配未使用的空间;
- len:分配已使用的空间大小
- buf:char类型的数组
注:新的版本中SDS结构已调整:
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 {
uint64_t len; // 已使用的空间大小
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[]; // 字节数组 保存字符串
};
2、与C字符串区别(为什么一个字符串要定义成这样的数据结构?)
-
获取字符串长度由O(n)变为O(1),直接读取len字段即可知道(Redis关心性能);
-
空间分配时杜绝缓存溢出:Redis在存储数据之前会检查SDS空间是否足够,不够会先扩展空间然后再进行拼接;
Redis在分配内存时,会额外多分配一些内存。如:当SDS长度小于1M时,会再多分配len大小的未使用空间,buf数组长度就是为 2*len +1;当SDS长度大于1M时,会多分配1M。通过这种方法,Redis可以减少连续执行字符串增长操作所需的内存重分配次数。
二、双向链表 linkedlist
Redis中的链表结构是由 list结构 + 双向链表结点 组成的。
Redis中链表特点如下:
- 双端:每个链表结点都有prev和next指针,获取某个节点的前、后置节点时间复杂度都是O(1);
- 表头指针和表尾指针:通过he