当前位置:首页 > 问答 > 正文

Redis那些数据类型到底是咋支持的,深入聊聊它用的数据结构和原理

要搞清楚Redis的数据类型是怎么支持的,我们得先明白一个关键点:Redis是一个内存数据库,它最核心的速度优势来自于把所有数据都放在内存里操作,内存是宝贵的,不能胡乱存放,所以Redis在底层用了很多精妙的数据结构来平衡速度和内存占用,它做的不是简单地用一个数据结构对应一个数据类型,而是“看菜下饭”,根据数据的大小、数量等因素,在同一种数据类型背后,选择最合适的底层实现,这个机制在Redis里叫做“编码”(encoding)。

下面我们就来聊聊几种常见数据类型背后的门道。

字符串(String)

字符串是Redis最基础的类型,你以为它就是个简单的字符数组?没那么简单,Redis的字符串是“智能”的。

  • 简单情况:当你存的是一个短字符串,或者数字时,Redis会用一种叫 SDS(Simple Dynamic String,来源:Redis设计与实现) 的结构来存,SDS比C语言自带的字符串聪明,它记录了字符串的长度,所以获取长度速度极快(O(1)复杂度),而且是二进制安全的,可以存任何数据,比如图片或者序列化后的对象。
  • 特殊情况:如果你存的是一个整数,set age 30,Redis会识别出来,它底层就直接用整数来存储这个值,这样在做 incr age 这种增加操作时,就不用先把字符串转成整数,操作完再转回去,直接进行CPU擅长的整数运算,速度飞起。
  • 大块头情况:当字符串的值非常大(比如超过44字节,这个阈值版本不同会变化),Redis就不会再用简单的SDS了,而是会改用一种叫 embstr 的编码方式,或者更进一步的,直接分配一块独立的内存来存储这个大字符串,以减少管理开销。

同样是String类型,背后可能对应着三种不同的存储方式,Redis会自动选择最有效率的一种。

Redis那些数据类型到底是咋支持的,深入聊聊它用的数据结构和原理

列表(List)

列表就是有序的字符串序列,支持从两头插入弹出,它的底层实现有两个选择:

  • 压缩列表(ziplist,来源:Redis设计与实现):当列表里的元素数量少,且每个元素本身也都是小字符串时,Redis会用压缩列表,这东西可以理解为一种“紧凑型”的数组,它把所有元素紧挨着存放,能极大地节省内存,比如你的列表是 [“hello”, “world”, “1”],用压缩列表存就非常划算。
  • 双向链表(linkedlist):一旦列表的元素数量变多,或者某个元素变得很大,再使用压缩列表进行插入、删除操作效率就低了,因为需要重新分配内存,这时Redis就会把压缩列表升级成一个标准的双向链表,双向链表的每个节点都有指向前一个和后一个节点的指针,这样在任意位置插入删除都很快,但代价是每个节点都需要额外的指针空间,比压缩列表更占内存。

列表的底层是动态的,从小到大的成长过程中,它会“换装”,从节省内存的压缩列表换成了操作灵活的双向链表。

哈希(Hash)

Redis那些数据类型到底是咋支持的,深入聊聊它用的数据结构和原理

哈希就是键值对的集合,比如存一个用户对象:name: “张三”, age: “25”

  • 压缩列表(ziplist):和列表类似,当哈希表中的字段数量很少,且所有字段名和字段值都是短字符串时,Redis会使用压缩列表,它会依次存放 field1, value1, field2, value2 这样的键值对,非常紧凑。
  • 哈希表(hashtable,来源:Redis设计与实现):当哈希表变大或者出现了长的字段名/值时,Redis就会切换到真正的哈希表结构,这个哈希表和很多编程语言里的字典(Dictionary)类似,通过计算键的哈希值来快速定位数据,查找、插入、删除的速度都非常快,接近O(1)。

集合(Set)

集合的特点是无序且元素唯一。

  • 整数集合(intset,来源:Redis设计与实现):当集合里的所有元素都是整数,并且数量不多时,Redis会使用整数集合,它就是一个有序的整数数组,利用有序性可以用二分查找来快速判断元素是否存在,非常节省内存。
  • 哈希表(hashtable):一旦你往集合里放了一个非整数的字符串,或者整数数量超过阈值,Redis就会将底层实现切换为哈希表,在集合的哈希表实现中,每个元素的键就是集合成员,而值则是一个固定的空值(比如NULL),因为哈希表的键本身就是唯一的,正好符合集合的特性。

有序集合(ZSet)

Redis那些数据类型到底是咋支持的,深入聊聊它用的数据结构和原理

这是Redis最复杂的数据结构,它每个元素都有一个分数(score)用于排序,既要保证按分数快速排序,又要能根据成员名快速查找。

  • 压缩列表(ziplist):同样,元素少且小时,用压缩列表,交替存储 member1, score1, member2, score2,并保证按分数顺序存储。

  • 跳表(skiplist) + 哈希表(hashtable)的组合结构(来源:Redis设计与实现):这是有序集合的标准形态,它同时使用了两种数据结构:

    • 跳表:一种可以理解为“带有多层索引的有序链表”,它允许像二分查找一样快速定位元素,范围查询(比如取分数在100到200之间的所有成员)效率极高。
    • 哈希表:这个哈希表的作用是存储成员到分数的映射,这样当你需要查询某个具体成员的分数时,速度是极快的O(1)。

    这种组合拳使得有序集合既能高效按分数排序和范围查询,又能快速进行单点查找,虽然占用内存多一些,但功能非常强大。

总结一下

Redis数据类型的花样背后,是它对效率和内存的极致权衡,它通过一套动态的编码机制,在数据量小的时候,优先选择更节省内存的紧凑型结构(如压缩列表、整数集合);当数据量变大或结构变得复杂时,再无缝切换到性能更高的通用结构(如哈希表、跳表),这种“因地制宜”的策略,使得Redis在绝大多数常见场景下都能保持飞快的速度和较低的内存消耗,这正是它如此强大的核心秘密之一。