Redis数据结构底层实现

200 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

概述

Redis的底层数据结构一共有6种,分别是字符串、list列表、hash、集合和有序结合。

  • 底层数据结构

    • 压缩列表:数组,数组中的每一个元素都对应保存一个数据,表头有三个字段zllbytes,zltail和zllen,表尾还有zlend。查头和尾很方便,其他元素就是逐个查找。在目前的版本中基本已经废弃
    • listpack 也叫紧凑列表,它的特点就是用一块连续的内存空间来紧凑地保存数据,同时为了节省内存空间,listpack 列表项使用了多种编码方式,来表示不同长度的数据,这些数据包括整数和字符串。
    • 跳表:在链表的基础上增加了多级索引,通过索引位置的跳转,实现数据的快速定位。在多级索引上跳来跳去,最后定位到元素

详解

1. 字符串

Redis的字符串是动态字符串和int,是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。

  • 字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。

应用场景

  • 计数器 如果字符串的内容是一个整数,那么还可以将字符串当成计数器来使用。
  • 过期和删除 字符串可以使用del指令进行主动删除,可以使用expire指令设置过期时间,到点会自动删除,这属于被动删除。可以使用ttl指令获取字符串的寿命。
  • 缓存对象
  • 分布式锁
  • 共享session信息

2. List双向链表

  • 负下标,表示倒数第几个
  • 队列/堆栈,结合使用rpush/rpop/lpush/lpop四条指令
  • 定长列表:维持定长列表的指令是ltrim,需要提供两个参数start和end,表示需要保留列表的下标范围,范围之外的所有元素都将被移除。
  • 快速列表:将链表和压缩列表结合变成quicklist,将多个压缩列表使用双向指针串起来使用
  • 在 Redis 3.2 版本之后,List 数据类型底层数据结构就只由 quicklist 实现了,替代了双向链表和压缩列表

应用场景

  • 消息队列

3. hash

hash,使用二维结构,第一维是数组,第二维是链表,hash的内容key和value存放在链表中,数组里存放的是链表的头指针。

  • 扩容:当hash内部的元素比较拥挤时(hash碰撞比较频繁),就需要进行扩容。扩容需要申请新的两倍大小的数组,然后将所有的键值对重新分配到新的数组下标对应的链表中(rehash)。

  • 渐进式rehash:同时保留新旧两个hash结构,在后续的定时任务和hash结构的读写指令中将旧结构的元素组建迁移到新的结构中,避免扩容导致的线程卡顿。

在 Redis 7.0 中,压缩列表数据结构已经废弃了,交由 listpack 数据结构来实现了。一般对象使用String+Json存储,对象中某些频繁变化的属性可以考虑抽出来用Hash类型存储。

应用场景

  • 购物车

4. set和sortedset

  • set,使用hash结构或者是整数集合实现的,所有的value指向同一个内部值

  • sortedset,实现两个数据结构,一个是hash,一个是跳跃列表,hash作用是关联元素value和权重score,保障元素value的唯一行,通过元素value找到相应的score值。跳跃列表的目的在于给元素value排序,根据score的范围获取元素列表。

    • 一方面它等价于Java的数据结构Map<String, Double>,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。
    • 跳跃列表:层级制串联所有数据

应用场景:

  • set:点赞和共同关注,抽奖活动
  • sortedset:最新列表,排行榜

总结

Redis底层数据结构的实现

  • string:简单动态字符串或者int
  • 列表:双向链表+压缩列表,后来变成quicklist(双向+压缩列表的综合体)
  • hash:压缩列表+哈希表,后来压缩列表变成listpack数据结构来实现
  • 集合:哈希表+整数数组
  • 有序集合:跳表+压缩列表

如果想要高效使用Redis,记住口诀:单元素操作是基础;范围操作很耗时,统计操作通常高效,例外情况有几个

参考文献

极客:Redis核心设计和实践

通俗易懂的Redis数据结构基础教程:juejin.cn/post/684490…