Redis五大基本数据结构底层了解

一、String 字符串结构(最常用)

1.1 底层存储方式

Redis String 底层并非简单的字符串,而是 SDS(简单动态字符串) 实现。

SDS 核心结构:

  • len:已使用字符串长度

  • free:剩余空闲缓冲区长度

  • buf\[\]:实际存储字符数组

Redis 根据字符串长度自动适配三种编码:

  • int编码:纯数字且长度短,直接存整型

  • embstr编码:短字符串(≤44字节),内存连续存储,节省空间

  • raw编码:长字符串(>44字节),独立内存存储

1.2 String 核心优点

  • 读写性能极高:O(1) 时间复杂度,操作简单高效

  • 二进制安全:可存储图片、字节流、序列化数据,不会被截断

  • 支持原子操作:INCR、INCRBY 实现原子计数,无并发问题

  • 动态扩容:SDS 自动扩容,无需手动维护长度

  • 兼容绝大部分基础缓存场景,通用性最强

1.3 String 核心缺点

  • 存储对象冗余大:存储对象需要整体序列化/反序列化,无法单独更新某个字段

  • 大Key风险极高:单个Value过大容易形成BigKey,阻塞主线程

  • 字段更新低效:修改单个字段需要全量覆盖写入

2.4 适用场景

  • 常规缓存数据、用户信息、配置信息、字典数据

  • 计数器场景:点赞数、阅读量、粉丝数、访问统计

  • 分布式锁、全局唯一ID、限流计数

  • 短链接、验证码、Token、Session 存储


二、Hash 哈希结构(对象专属)

2.1 底层存储方式

Redis Hash 底层为双编码自适应结构(基于Redis7),根据元素数量和字段长度自动切换存储模式:

  • listpack(紧凑列表):字段数 <512 且所有字段值 <64字节,采用连续内存紧凑存储,无冗余字段、无连锁更新问题,内存利用率极高

  • hashtable(字典):超出阈值自动转为哈希表结构,支持高效随机读写

  • ziplist(压缩列表):字段数 <512 且所有字段值 <64字节,采用连续内存压缩存储,极度省内存

  • hashtable(字典):超出阈值自动转为哈希表结构,支持高效读写

本质:一个 Key 对应多个 field-value 键值对,适合结构化对象存储。

2.2 Hash 优点

  • 结构化存储:完美适配对象数据,无需序列化

  • 字段级更新:支持单独修改某个字段,无需全量更新

  • 内存占用低:ziplist 压缩存储,比 String 序列化更节省内存

  • 读写灵活:可单查、单改、批量查,适配业务灵活变更

2.3 Hash 缺点

  • 不支持过期单独字段:只能对整个 Hash Key 设置过期,无法针对某个 field 过期

  • 超大Hash易形成BigKey:字段过多会降级为hashtable,内存暴涨、性能下降

  • hgetall 高危阻塞:一次性获取所有字段会阻塞主线程

2.4 适用场景

  • 用户信息缓存(昵称、头像、性别、手机号)

  • 商品基础信息、店铺信息、设备信息

  • 购物车数据、权限配置、多字段结构化数据

  • 频繁局部更新的业务对象


四、List 列表结构(有序可重复队列)

4.1 底层存储方式

Redis List 底层采用 quicklist(快速列表)(基于Redis7),整体为「双向链表+listpack」的组合结构,彻底替代Redis6及更早版本的ziplist节点。

结构原理:

  • 将多个 listpack 紧凑节点,通过双向链表串联

  • 节点内紧凑压缩存储、节点间通过指针关联

  • 兼顾极低内存占用头尾极致高效操作,彻底解决旧版本ziplist连锁更新性能问题

特性:有序、可重复、头尾操作极快、中间操作慢

4.2 List 优点

  • 头尾操作O(1):LPUSH、RPUSH、LPOP、RPOP 性能极高

  • 内存紧凑:quicklist 压缩存储,内存利用率高

  • 天然队列、栈结构:轻松实现消息队列、栈模型

  • 支持范围查询、分页查询

4.3 List 缺点

  • 中间元素操作慢:查询、修改中间数据为 O(n) 级开销

  • 数据只增不减易形成大Key:日志、队列长期堆积会无限拉长

  • 不适合随机访问场景

4.4 适用场景

  • 简单消息队列、任务队列、异步队列

  • 用户浏览记录、操作日志、时间线数据流

  • 排行榜简单时序数据、最新列表

  • 栈、队列模型业务场景


五、Set 集合结构(无序不可重复)

5.1 底层存储方式

Redis Set 底层双编码自适应:

  • intset(整数集合):元素全为整数、数量较少时,紧凑数组存储,极致省内存

  • hashtable(字典):含非整数或元素过多,自动转为哈希表

核心特性:无序、自动去重、元素唯一、支持集合运算

5.2 Set 优点

  • 天然去重:插入自动去重,无需业务判断

  • 高效判重:元素存在性判断 O(1)

  • 支持集合运算:交集、并集、差集,轻松实现共同好友、共同关注

  • 增删改查性能优秀

5.3 Set 缺点

  • 无序存储:无法保证数据顺序,不适合排序场景

  • 不支持排序查询:无自带排序能力

  • 海量元素遍历耗时较高

5.4 适用场景

  • 点赞用户、收藏用户、关注列表(自动去重)

  • 社交关系:共同好友、共同关注、粉丝比对、推荐好友

  • 黑名单、白名单、IP封禁列表

  • 海量数据去重、存在性校验


六、ZSet 有序集合(排行榜专属)

6.1 底层存储方式

ZSet(有序集合)底层同样采用双编码自适应(基于Redis7):

  • listpack 紧凑列表:元素数量少、分值较小时,使用listpack压缩存储,内存精简、无连锁更新问题

  • skiplist + dict(跳表+字典):数据量超出阈值后自动降级为跳表结构,保障有序范围查询性能

核心结构:

  • dict字典:保证元素唯一性,O(1)快速查元素分值

  • skiplist跳表:保证有序排序、范围查询、区间分页高效

特性:唯一元素 + 可排序 + 可范围查询

6.2 ZSet 优点

  • 自带排序能力:根据 score 分值自动升序/降序

  • 去重+排序双特性:元素唯一、有序排列

  • 范围查询极强:支持区间分页、TopN 查询

  • 跳表结构查询、插入、删除性能均衡优秀

6.3 ZSet 缺点

  • 内存占用最高:同时维护字典+跳表,结构最复杂

  • 更新分值开销略高:排序结构调整有一定成本

  • 不适合简单去重、无序存储场景(大材小用)

6.4 适用场景

  • 各类排行榜:热度榜、销量榜、积分榜、点赞榜

  • 延时队列、定时任务排序(score 存时间戳)

  • 带权重排序的业务、优先级任务队列

  • 分页有序数据、区间筛选业务


七、五大数据结构核心对比 & 选型总结(面试必背)

数据结构 有序性 重复性 底层核心 最佳场景
String 无序 可重复 SDS动态字符串 通用缓存、计数器、分布式锁
Hash 无序 field唯一 listpack/hashtable 结构化对象存储、多字段更新
List 有序 可重复 quicklist+listpack 队列、时序日志、列表数据
Set 无序 不可重复 intset/hashtable 去重、社交关系、黑名单
ZSet 有序 不可重复 listpack+跳表+字典 排行榜、延时队列、有序权重数据

八、Redis6 与 Redis7 底层数据结构核心差异对比

全文基于 Redis7 最新底层规范编写:Redis 7.0 核心底层架构升级为彻底废弃 ziplist 压缩列表,全面使用 listpack 紧凑列表替代,解决了 ziplist 内存冗余、更新连锁扩容、遍历越界等历史痛点,本节详细对比 Redis6 与 Redis7 底层差异,帮助理解新版Redis核心优化。

8.1 五大数据结构底层实现版本对比表

数据结构 Redis6 底层实现 Redis7 底层实现 核心升级说明
String SDS(int/embstr/raw) SDS(优化扩容逻辑) 结构无变更,优化内存分配,减少内存碎片
Hash ziplist + hashtable listpack + hashtable 彻底移除ziplist,低数据量下使用listpack压缩存储,内存更紧凑
List quicklist + ziplist quicklist + listpack quicklist底层节点由ziplist替换为listpack,修复连锁更新问题
Set intset + hashtable intset + hashtable 无底层变更,整数集合与哈希表逻辑完全兼容
ZSet ziplist + skiplist + dict listpack + skiplist + dict 少量数据时用listpack替代ziplist,排序读写性能小幅提升

8.2 核心升级:Listpack 替代 Ziplist 优势详解

Ziplist 是 Redis 低版本经典压缩结构,但存在致命设计缺陷,Redis7 推出 Listpack 完全替代,核心优化点如下:

  • 解决连锁更新问题:ziplist 新增/修改元素导致长度变化时,如果长度超过254会触发后续所有节点连锁更新,性能极差;listpack 每个节点独立存储,互不影响,彻底杜绝连锁更新开销。

  • 内存占用更低:listpack 去除 ziplist 冗余的前置长度字段,结构更精简,同等数据量内存占用降低 10%~30%。

  • 遍历更安全:ziplist 存在反向遍历越界风险,listpack 头尾独立标识,双向遍历安全稳定。

  • 读写性能更高:避免大量内存重拷贝,高频更新场景性能提升显著。

8.3 各版本适配与生产选型建议

  • Redis6 适用场景:老旧项目平稳运行、无需高频更新小容量 Hash/List/ZSet 数据,兼容旧环境无需升级。

  • Redis7 推荐场景:高并发、高频更新、海量小元素存储场景(商品Hash、时序List、排行榜ZSet),优先升级,性能与内存利用率更优。

  • 兼容性说明:Redis7 对外 API 完全兼容 Redis6,业务代码无需改造,仅底层存储结构优化,无业务侵入性。

相关推荐
如竟没有火炬1 小时前
最大矩阵——单调栈
数据结构·python·线性代数·算法·leetcode·矩阵
真实的菜2 小时前
Redis 从入门到精通(十二):典型业务场景实战 —— 排行榜、限流器、秒杀系统、Session 共享
数据库·redis·python
你想考研啊2 小时前
mysql数据库导出导入
数据库·mysql·oracle
十年编程老舅3 小时前
Linux DRM:底层逻辑与实践架构
数据库·mysql
The Sheep 20233 小时前
Vue复习
linux·服务器·数据库
云边有个稻草人3 小时前
深度解析:KingbaseES高可用架构落地原理与生产运维实战
数据库·读写分离·数据库运维·金仓数据库·国产数据库技术·数据备份恢复
满天星83035774 小时前
【Qt】信号和槽(二) (自定义信号和槽)
开发语言·数据库·qt
我不介意孤独5 小时前
04-记忆系统为什么向量数据库不够用
数据库·人工智能·资源隔离·agent infra
AOwhisky5 小时前
MySQL 学习笔记(第六期):MySQL 备份与恢复
运维·数据库·笔记·学习·mysql·云计算