redis之五种基本数据类型

redis之五种基本数据类型

💡 原文中文,约4900字,阅读约需12分钟。
📝

内容提要

本文介绍Redis五种基本数据类型及其底层实现:String支持int、embstr、raw编码,底层采用SDS动态字符串,可O(1)获取长度并支持二进制安全;List在3.2版本后使用quicklist,兼顾ziplist与linkedlist的优点;Set使用intset或hashtable,整数集合支持升级;Sorted Set使用ziplist或skiplist加dict,实现排序与快速查找;Hash使用ziplist或hashtable存储对象。理解这些结构有助于按场景选择合适的类型。

🔎

延伸解读

编码选择背后的内存与性能权衡

文章指出 String 的 embstr 与 raw 编码以 44 字节为界,embstr 一次分配连续内存,raw 需两次分配。这提示小字符串用 embstr 更省分配开销,但长度超过 44 字节后转为 raw。类似地,List、Set、Sorted Set、Hash 在数据量小时倾向 ziplist 或 intset,数据量大时转为 quicklist、hashtable 或 skiplist。理解这些阈值有助于预判内存布局和操作性能。

SDS 如何解决 C 字符串的短板

文章用 SDS 结构说明 String 的底层优势:len 字段使长度获取为 O(1),而 C 字符串需遍历;SDS 提供 API 判断并扩充空间,减少频繁内存分配释放;buf 以二进制方式处理并用 len 判断结束,因此支持二进制安全。这些特性直接影响 String 存储非文本数据时的可靠性,也解释了为何不直接沿用 C 传统字符串。

quicklist 与 skiplist 的设计取舍

List 在 3.2 后使用 quicklist,宏观是双向链表、每个节点挂一个 ziplist,在 ziplist 的连续内存优势与 linkedlist 的碎片化问题之间取得平衡。Sorted Set 在 skiplist 编码下同时使用 zskiplist 和 dict:前者支持快速范围查询,后者快速定位单个元素。文章还提到 ziplist 连锁更新概率低但复杂度高,说明这些结构并非没有代价,需结合数据规模理解。

intset 升级与编码转换的注意点

Set 在满足条件时使用 intset,其 contents 元素类型由 encoding 决定;当插入更大整型时,需对现有元素逐个升级,以节省小整型时的内存,且目前不支持降级。文章还列出各类型在数据量或元素长度变化时从紧凑编码转为 hashtable、skiplist 等。这意味着同一键的底层编码可能随写入变化,排查内存或性能问题时不能只看逻辑类型。

❓

Q&A

Redis的String类型底层是怎么存储的?为什么不用C语言字符串?

String底层使用简单动态字符串(SDS)实现。SDS结构包含len(已使用字节数)、free(未使用字节数)和buf(字节数组)。相比C字符串,SDS优势在于:O(1)获取长度(直接读len),二进制安全(用len判断结束而非空字符),以及通过空间预分配和惰性释放减少内存分配次数。

Redis的List在3.2版本后底层用什么数据结构?有什么好处?

Redis 3.2版本后List使用quicklist作为底层数据结构。quicklist是ziplist和双向链表的结合,宏观上是双向链表,每个节点挂一个ziplist。它平衡了ziplist在数据量大时性能下降和双向链表内存碎片多的问题,兼顾了内存和性能。

Redis的Set类型在什么情况下使用intset编码?intset升级是什么?

当Set满足所有元素都是整数且元素数量不超过512个(默认配置)时,使用intset编码,否则使用hashtable。intset升级是指当插入一个超出当前编码范围的大整数时,intset会将所有元素的编码升级为更大的类型(如int16升级到int32),以保持数组的统一性。升级过程不可逆,不支持降级。

Redis的Sorted Set底层是如何实现排序和快速查找的?

Sorted Set在数据量较大时使用skiplist编码,其底层结构为zset,包含一个zskiplist(跳跃表)和一个dict(字典)。zskiplist负责维护元素按score排序,支持范围查询;dict则保存元素到score的映射,实现O(1)的单元素查找。两者结合实现了高效的范围查询和点查询。

Redis的Hash类型在什么条件下使用ziplist编码?

当Hash满足以下两个条件时使用ziplist编码:哈希表中键值对的数量小于512个,且所有键和值的字符串长度都小于64字节。不满足任一条件时,Hash会转换为hashtable编码。

Redis的String类型有哪几种编码方式?embstr和raw有什么区别?

String有三种编码:int(存储整型值)、embstr(字符串长度≤44)、raw(字符串长度>44)。embstr和raw都使用SDS存储,区别在于内存分配:raw需要两次内存分配(redisObject和SDS分开),而embstr一次分配连续内存(redisObject和SDS在一起)。embstr在字符串较小时更高效,能更好利用CPU缓存。

🏷️

标签

➡️

继续阅读