Redis常用数据类型

目录

Redis常用数据类型

String

存储:

底层实现

SDS动态字符数组

缓冲区溢出

Hash

压缩列表

哈希表

List

Zset

底层实现:

ziplist(redis6之后被listpack替代)

prevlen

连锁更新问题

listpack

skiplist + 哈希表

哈希表

扩容

skiplist

核心结构

查询操作逻辑

插入操作逻辑

删除操作逻辑

为什么用跳表不用b+数

实现复杂度与代码维护

写入性能与重平衡代价

Set

扩展数据类型

Bitmap

HyperLogLog

Geo

Stream


String

是二进制安全的, Redis 不会对存储的内容做任何编码 / 解码处理,能存储任意格式的二进制数据

存储:

文本字符,数字,二进制数据

自增自减等操作是原子性的

支持设置过期时间

单个value最大容量512mb

底层实现

SDS动态字符数组

自动预分配(扩容) / 惰性释放(缩容),减少内存操作次数


缓冲区溢出

C 语言提供的字符串操作函数,大多数都是不安全的,因为这些函数把缓冲区大小是否足够用交由开发者来保证,程序内部并不会判断缓冲区大小是否足够用,当发生了缓冲区溢出就有可能造成程序异常结束。

SDS 结构里引入了 alloc 和 len 成员变量, 通过 alloc - len 计算,可以算出剩余可用的空间大小,这样在对字符串做修改操作的时候,就可以由程序内部判断缓冲区大小是否足够用。当判断出缓冲区大小不够用时,Redis 会自动将扩大 SDS 的空间大小,以满足修改所需的大小。


Hash

压缩列表

哈希对象保存的所有键值对的 键和值的字符串长度都小于等于 64 字节;

哈希对象保存的 键值对数量小于等于 512 个。

哈希表

超过以上两个阈值的其中一个就会转换成哈希表

List


Zset

ZSet 的核心是「有序」+「唯一」:member(成员)唯一,按 score(分数)排序(score 相同则按 member 字典序),value是set集合实现的,无序且唯一

底层实现:

元素数量(member 总数)小于128且元素(member )大小小于64用压缩列表,反之跳表

ziplist(redis6之后被listpack替代)

prevlen

若前一个 entry 的长度 < 254 字节:prevlen用1 字节存储(直接存长度数值);

若前一个 entry 的长度 ≥ 254 字节:prevlen用5 字节存储(第 1 字节固定为0xFE标记,后 4 字节存长度数值)。

连锁更新问题

扩容/缩容,根据prevlen的特性

连锁更新会导致多次内存重新分配 + 大量数据移动

listpack


skiplist + 哈希表

哈希表

扩容

触发时机由负载因子决定


skiplist

核心结构

多层链表

查询操作逻辑

从最高层开始,每层内多次跳转(每次判断后继是否≤目标,是则跳转,最后一个大于目标值的节点是该层的前驱节点,为后续做插入操作做准备),直到不能跳为止,再向下一层,接着该节点继续跳转(上层的所有元素是下层的集合,也就是说下一层一定包含上一层的所有元素,这样才能接着上一层的元素继续遍历);重复此过程直到 L0 层,最终验证目标是否存在,在L0 层找到值相等的节点则返回” —— 总跳转次数是 O (log n),而非 O (n)(遍历所有节点)。

插入操作逻辑

先查询,需要确定晋升层数,通过随机算法,在0~1之间随机选一个数,小于0.25就晋升一层,一直到大于0.25就停止,在所有晋升的层中插入节点,前驱节点的后继指针指向新节点,新节点的后继指针指向原前驱的后继节点(若存在,不存在就置为null)。

删除操作逻辑

先查询,对目标节点存在的层级,将前驱节点的后继指针直接指向目标节点的后继指针节点,跳过目标节点(无需额外维护前驱指针),目标节点等待被gc回收

为什么用跳表不用b+数

内存 vs. 磁盘的设计初衷 (最重要的原因)

B+ 树是为磁盘 I/O 优化的: B+ 树的设计核心是降低树的高度,从而减少磁盘 I/O 次数。

Redis 是纯内存操作:在内存中,没有 “磁盘 I/O” 的瓶颈。B+ 树为了减少高度而设计的复杂页管理机制,在内存场景下显得多余且笨重。

实现复杂度与代码维护

B+ 树:插入和删除可能引发节点的分裂(Split)和合并(Merge),甚至需要对整棵树进行重平衡,代码量大且难以调试。

跳表(Skip List): 本质上是 “多层链表”。其插入、删除逻辑主要是修改指针,代码实现非常简洁

写入性能与重平衡代价

B+ 树:当插入数据导致页分裂时,可能需要移动大量数据或改变树结构

跳表的局部性:跳表的插入和删除操作是局部的。插入一个节点只需要修改前后节点的指针

Set

扩展数据类型

Bitmap

HyperLogLog

Geo

Stream

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐