常见数据结构
键值类型数据库
-
Key 常见类型:String
-
Value 常见类型
数据类型 数据说明 String “hello world” Hash { name: “Jack”, age : 21 } List [ A → B → C → D ] Set { A, B, C },基本类型,无序集合 SortedSet { A : 1, B : 2, C : 3 },有序集合 GEO { A : (12.3, 30.5) } BitMap 0101010101010010101 HyperLog 0101010101010101010
其他数据库
- 文档类型 (MongoDB)
- 列类型 (HBase)
- Graph 类型 (Neo4j)
一、动态字符串 SDS
-
定义:Simple Dynamic String 简单动态字符串,Redis 实现的字符串
-
功能:
- 获取长度:快速获取字符串长度 (时间复杂度 O(1) )
- 动态扩容:可以修改,并且预分配内存空间可以减少内存分配次数
- 二进制安全:SDS 记录了字符串长度,不会因为 ‘\0’ 提前结束
-
SDS 结构体组成
属性 说明 unit8_t len buf已保存的字符串字节数,不包含结束标示 unit9_t alloc buf申请的总的字节数,不包含结束标示 unsigned char flags 不同SDS的头类型,用来控制SDS的头大小,有 5 种,分别为5 / 8 / 16 / 32 / 64 buf[] 实际存储的内容 -
动态扩容(内存预分配)
- 字符串小于 1 M :新空间为新字符串长度的 2 倍 + 1
- 字符串大于 1 M :新空间为新字符串长度 + 1M + 1
二、IntSet
-
定义:一种 set 集合的实现方式,基于整数数组实现,类似 Set,但是只能存储数值
-
特点
- 唯一有序:Set 集合中的元素唯一并且有序
- 类型升级:contents 元素超出 encoding 限制时,会自动升级 encoding 方式,可以节省内存空间
- 二分查找:底层采用二分查找来查询
-
组成
属性 说明 unit32_t encoding contents[] 的编码方式,支持存放16位(short)、32位(int)、64位(long)整数 unit32_t length contents[] 中元素个数 int8_t contents[] 整数数组,保存集合数据
三、Dict
-
功能 :字典类,类似 java 的 HashTable,实现 key-value 映射关系
-
Dict 扩容
- 功能:降低哈希冲突,提高查询效率
- 实现方式:Dict 新增键值对时检查负载因子 (LoadFactor = used/size),如果 LoadFactor ≥ 1,并且服务器没有执行 BGSAVE 或 BGREWRITEAOF 等后台进程,或者 LoadFactor > dict_force_resize_ratio ,则执行 Dict Rehash 进行扩容
-
Dict 收缩
- 功能:节省内存空间
- 工作流程:每次删除 key-value 时检查负载因子,如果 LoadFactor < 0.1 则会做哈希表收缩
-
Dict Rehash
-
定义:扩容或收缩时,对哈希表中的每一个 key 重新计算索引,插入新的哈希表,这个过程称为rehash
-
工作流程
-
计算新 hash 表的 realeSize,值取决于当前要做的是扩容还是收缩:
- 如果是扩容,则新size为第一个大于等于dict.ht[0].used + 1的2^n
- 如果是收缩,则新size为第一个大于等于dict.ht[0].used的2^n (不得小于4)
-
按照新的realeSize申请内存空间,创建dictht,并赋值给dict.ht[1]
-
设置dict.rehashidx = 0,标示开始rehash
-
将dict.ht[1]赋值给dict.ht[0],给dict.ht[1]初始化为空哈希表,释放原来的dict.ht[0]的内存
-
将rehashidx赋值为-1,代表rehash结束
-
在rehash过程中,新增操作,则直接写入ht[1],查询、修改和删除则会在dict.ht[0]和dict.ht[1]依次查找并执行。这样可以确保ht[0]的数据只减不增,随着rehash最终为空
-
-
-
组成
属性 功能 Dict 存储字典类型和私有数据(hash函数),哈希表(两个,第二个用于rehash),rehashidx(rehash的进度),pauserehash:rehash是否暂停 DictHashTable 存储 entry 数组,hash表大小,哈希表大小的掩码(size-1),entry个数 DictEntry 存储 key-value 键值对,hash 冲突时的下一个 DictEntry 的指针
四、ZipList
-
定义 :一种特殊的“双端链表”,一系列特殊编码的连续内存块组成
-
功能 :节约内存空间(连续的内存空间,减少指针对内存的占用)
-
特点
- 占用连续内存空间,通过上一节点和本节点长度寻址,内存占用低
- 如果列表数据过多(链表过长),可能影响查询性能
- 增删较大数据时可能发生连续更新问题
-
组成
属性 类型 长度 功能 zlbytes unit32_t 4 byte 记录整个 ZipList 占用内存字节数 zltail unit32_t 4 byte 记录 ZipList 表尾结点距离压缩列表的起始地址字节数,用于快速定位表尾结点 zllen unit16_t 2 byte 记录 ZipList 包含的结点数量 entry 列表节点 不定 ZipList 的各个结点,结点长度由结点内容决定 zlend unit8_t 1 byte 标记 ZipList 的末端(特殊值 0xFF) -
结构
五、QuickList
-
定义 :ZipList 的升级版本,是一个节点为 ZipList 的双端链表
-
功能 :解决传统链表的内存占用问题,控制 ZipList 大小,提高内存空间申请效率(不必很大的连续内存空间)
-
配置参数
- list-max-ziplist-size:限制 ZipList 结点大小,正数为最大 ZipList entry 个数,负数为最大内存占用(-x 表示最大占用 4*x kb 内存)
- list-compress-depth:首尾不压缩节点的个数(x 表示首尾各x个 entry 不压缩),默认为 0(不进行压缩)
-
组成
属性 功能 head 头结点指针 tail 尾节点指针 count 所有 ZipList 的 entry 的总数 len ZipList 结点的总数量 QL_FILL_BITS ZipList 结点的 entry 上限 QL_COMP_BITS 首尾不压缩的结点数量 QL_BM_BITS 内存重分配时的书签数量及数组(一般用不到)
六、SkipList
-
定义 :一个双向链表,每个节点包含 score 和 level
-
功能 :通过多级指针,实现不同跨度的查找,解决顺序查找效率过低的问题
-
特点
- 结点按照 score 排序,score 一样则按照 ele 字典排序
- 每个节点可以包含多层指针,层数是 1 到 32 之间的随机数
- 不同层指针的跨度不同,层级越高跨度越大
- 增删改查效率与红黑树一致
-
zskiplist 组成
属性 功能 header / tail 头尾节点指针 length 节点数量 level 最大的索引层级(默认 = 1) -
zskiplistNode 组成
属性 功能 ele 结点存储的值(SDS 类型) score 结点分数,用于排序、查找 backward 前一节点指针 level[] 多级索引数组,包含 forward 和 span 两个元素 forward 下一个节点指针 span 索引跨度
七、RedisObject
-
定义
:Redis 对象系统的基础数据结构,用于封装不同类型的数据对象 -
功能
:统一管理Redis中的各种数据类型,实现对象共享和内存回收 -
组成
属性 功能 type 存储的数据对象的类型 encoding 存储的数据对象的底层编码方式 lru 该对象最后一次被访问的时间 refcount 对象引用计数器,被引用一次则 +1,计数器为 0 时可以被回收 prt 指向实际数据的指针