Redis 九大数据结构:从原理到实战场景

目录

[Redis 数据结构](#Redis 数据结构)

五大核心数据结构

String(字符串)

实际业务场景

Hash(哈希)

实际业务场景

List(列表)

特点

常用命令

实际业务场景

Set(集合)

特点

常用命令

实际业务场景

[Sorted Set(有序集合,ZSet)](#Sorted Set(有序集合,ZSet))

特点

常用命令

实际业务场景

四大扩展数据结构

Bitmap(位图)

特点

常用命令

实际业务场景

HyperLogLog(基数统计)

特点

常用命令

实际业务场景

Geospatial(地理空间)

特点

常用命令

实际业务场景

Stream(消息流)

特点

常用命令

实际业务场景

总结


前言

提到 Redis 的数据结构,很多人第一反应是 String、List、Hash、Set、Sorted Set 这五种。但在实际企业级应用中,Redis 还提供了另外四种强大的扩展数据结构,它们在某些特定场景下能发挥奇效。

本文系统梳理 Redis 的九大数据结构,包括 5种核心结构 + 4种扩展结构,重点剖析每个结构的特点、底层实现以及在真实业务中的应用场景。这不仅是一篇技术分享,也是我自己的复习笔记,希望能帮助你在实际项目中做出更合适的数据结构选型。

Redis 数据结构

Redis 之所以被称为"数据结构服务器",正是因为它提供了丰富的数据结构,远超简单的键值存储。这九种数据结构可以分为两类:

类别 数据结构 核心特点
核心结构 String、List、Hash、Set、Sorted Set 基础通用,覆盖大多数场景
扩展结构 Bitmap、HyperLogLog、GEO、Stream 针对特定场景的极致优化

下面我们逐一深入讲解。

五大核心数据结构

String(字符串)

String 是 Redis 中最基础的数据结构,也是新手最先接触的。它不仅能存文本,还能存整数、JSON、甚至是二进制数据。

特点

  • 二进制安全:String 可以存储任何数据,包括 JPEG 图片或序列化对象

  • 底层编码:根据值的长度自动选择 int、embstr 或 raw 编码,节省内存

  • 最大容量:单个 String 最大支持 512MB

  • 原子操作:INCR/DECR 系列命令保证高并发下的计数准确

常用命令

SETGETMSETMGETINCRDECRSETNX

实际业务场景

① 常规缓存:存储 Session 信息、用户 Token

复制代码
SET user:1000 '{"id":1000,"name":"张三"}' EX 3600

② 计数器:利用 INCR 原子性实现阅读数、点赞数、库存扣减

复制代码
INCR article:readcount:1001        # 阅读数+1
DECR product:stock:2001             # 扣减库存

③ 分布式锁:利用 SET NX EX 实现简单的分布式锁

复制代码
SET lock:order_001 "thread_id" NX EX 10

Hash(哈希)

Hash 是一个 String 类型的 Field 和 Value 的映射表,非常适合存储对象。你可以把它想象成 Python 的字典或 Java 的 HashMap。

特点

  • 对象化存储:可以独立操作对象中的某个字段,无需全量读写

  • 内存优化:字段较少时使用 ziplist(压缩列表)编码,内存占用极低

  • 字段级操作:支持对单个字段进行增减(HINCRBY)

常用命令

HSETHGETHGETALLHINCRBYHDELHEXISTS

实际业务场景

① 购物车:以用户ID为Key,商品ID为Field,商品数量为Value

复制代码
HSET cart:user_1001 sku_2001 2
HINCRBY cart:user_1001 sku_2001 1      # 数量+1

② 用户会话管理:存储用户登录态、最后活跃时间等

复制代码
HSET user:session:1001 username "张三" last_login "2025-12-09" cart_items 5

③ 对象存储:存储用户信息、配置信息等

复制代码
HSET user:1001 name "张三" age 25 city "北京"

List(列表)

List 是一个双向链表结构,支持从两端压入或弹出元素。它是有序的,元素可以重复。

特点
  • 双向操作:LPUSH/RPUSH、LPOP/RPOP 时间复杂度均为 O(1)

  • 阻塞特性 :支持 BLPOP/BRPOP,是实现消息队列的关键

  • 底层实现:使用 quicklist(双向链表 + 压缩列表)结构,兼顾内存效率和访问速度

常用命令

LPUSHRPUSHLPOPRPOPLRANGEBLPOPBRPOP

实际业务场景

① 轻量级消息队列:利用 LPUSH + BRPOP 实现生产者-消费者模型

复制代码
# 生产者
LPUSH task_queue "send_email_123"
# 消费者(阻塞等待)
BRPOP task_queue 0

② 最新动态/消息流:例如微博的最新评论列表

复制代码
LPUSH news:latest "news_id_1001"
LTRIM news:latest 0 99      # 保持最新100条
LRANGE news:latest 0 9      # 获取最新10条

③ 栈和队列

  • LPUSH + LPOP = 栈(LIFO)

  • LPUSH + RPOP = 队列(FIFO)

Set(集合)

Set 是一个无序的、自动去重的字符串集合。底层基于哈希表实现。

特点
  • 自动去重:无需业务侧做重复判断

  • 集合运算:支持交集(SINTER)、并集(SUNION)、差集(SDIFF)

  • O(1) 成员判断:SISMEMBER 命令效率极高

常用命令

SADDSREMSMEMBERSSISMEMBERSINTERSUNION

实际业务场景

① 标签系统:给文章打标签,或给用户打兴趣标签

复制代码
SADD article:1001:tags "Java" "Redis" "微服务"
SADD tag:Java:articles 1001 1002 1003
# 找出同时有Java和Redis标签的文章
SINTER tag:Java:articles tag:Redis:articles

② 社交关系(共同好友):利用交集计算共同好友

复制代码
SADD user:1001:friends 1002 1003 1004
SADD user:1002:friends 1001 1003 1005
SINTER user:1001:friends user:1002:friends   # 返回 {1003}

③ 抽奖系统:利用 SRANDMEMBER 随机抽取

复制代码
SADD lottery:20251225 user_1001 user_1002 user_1003
SRANDMEMBER lottery:20251225 1     # 随机抽1人(不删除)
SPOP lottery:20251225 1            # 随机抽1人(删除)

Sorted Set(有序集合,ZSet)

这是 Redis 中最"高级"的数据结构,在 Set 的基础上给每个元素关联了一个分数(score),内部通过**跳表(Skip List)**实现排序。

特点
  • 自动排序:根据 Score 自动维护顺序,插入即有序

  • 高效范围查询:ZRANGE 和 ZRANGEBYSCORE 性能极高

  • 权重控制:Score 可以是整数或双精度浮点数

  • 底层实现:跳表 + 哈希表,兼顾排序和快速查找

常用命令

ZADDZRANGEZREVRANGEZINCRBYZRANKZRANGEBYSCORE

实际业务场景

① 排行榜:这是 ZSet 最经典的场景

复制代码
ZADD leaderboard:game 5000 "player1" 4500 "player2" 4800 "player3"
ZREVRANGE leaderboard:game 0 2 WITHSCORES   # 获取TOP3
ZINCRBY leaderboard:game 100 "player1"      # player1加分

② 延迟队列:利用 Score 存储执行时间戳

复制代码
# 添加延迟任务(当前时间戳+30秒后执行)
ZADD delayed_queue <timestamp+30> "order_1001"
# 定时任务轮询:获取到期的任务
ZRANGEBYSCORE delayed_queue 0 <current_timestamp>

四大扩展数据结构

Bitmap(位图)

Bitmap 不是一种全新的数据结构,它实际上是基于 String 的位级操作,将每个 bit 位作为独立的存储单元。

特点
  • 极致节省空间:一个 bit 位只占 1/8 字节,800 万用户仅需 1MB 内存

  • 位运算支持:支持 AND、OR、XOR、NOT 等位运算

  • 适合二值状态:只有 0 和 1 两种状态的场景

常用命令

SETBITGETBITBITCOUNTBITOPBITPOS

实际业务场景

① 用户签到:以用户ID为偏移量,签到记为1

复制代码
SETBIT sign:2025:12:user:1001 9 1        # 12月9日签到(偏移量从0开始)
BITCOUNT sign:2025:12:user:1001          # 统计当月签到天数

② 活跃用户统计:每天一个 Bitmap,用户登录则标记

复制代码
SETBIT active:2025-12-09 1001 1          # user_id=1001 今日活跃
BITOP AND active_7days active:2025-12-03 ...   # 统计连续7天活跃用户

③ 布隆过滤器底层:实现简单的去重机制

HyperLogLog(基数统计)

HyperLogLog 是一种概率性数据结构,用于估算集合的基数(唯一元素个数),以极小的内存消耗换取统计结果。

特点
  • 内存极小:每个 HyperLogLog 固定占用约 12KB 内存,即可统计上亿级唯一元素

  • 误差可控:标准误差约为 0.81%

  • 支持合并:PFMERGE 可以合并多个 HyperLogLog

常用命令

PFADDPFCOUNTPFMERGE

实际业务场景

① UV 统计:统计页面独立访客数

复制代码
PFADD uv:2025-12-09 "192.168.1.1" "192.168.1.2" "192.168.1.1"
PFCOUNT uv:2025-12-09           # 返回2

② 多日去重统计:合并多天的 UV 数据

复制代码
PFMERGE uv:week1 uv:day1 uv:day2 uv:day3
PFCOUNT uv:week1                # 周去重UV

③ 亿级用户去重:如广告投放的曝光用户去重

复制代码
如果用 Set 存储,1 亿用户 ID 需要 1GB+ 内存

用 HyperLogLog 只需 12KB,误差不到 1%

注意:HyperLogLog 只适合近似统计,不能用于精确计数场景(如金额、库存)

Geospatial(地理空间)

GEO 是基于 Sorted Set 实现的,专门用于存储地理位置(经纬度)和计算距离。

特点
  • 位置存储:存储经度、纬度,支持名称关联

  • 距离计算:支持计算两点之间的直线距离

  • 范围查询:支持查找指定半径内的所有位置

常用命令

GEOADDGEODISTGEORADIUSGEORADIUSBYMEMBER

实际业务场景

① 附近的人/店铺:基于位置推荐附近商家

复制代码
GEOADD restaurants 116.397 39.908 "故宫店" 116.405 39.915 "王府井店"
GEORADIUS restaurants 116.40 39.91 5 km   # 查询附近5公里内的店铺

② 打车/外卖场景:乘客叫车时查找附近司机

复制代码
GEOADD drivers:online 116.397 39.908 "driver_1001"
GEORADIUS drivers:online 116.40 39.91 3 km   # 查找3公里内的在线司机

③ 两地距离计算

复制代码
GEODIST restaurants "故宫店" "王府井店" km   # 返回两地距离(公里)

Stream(消息流)

Stream 是 Redis 5.0 引入的数据结构,专为消息队列场景设计,提供了完整的消息持久化、消费者组和消息确认机制。

特点
  • 消息持久化:消息不会因为消费后立即删除,支持历史回溯

  • 消费者组:支持多个消费者组独立消费同一条消息,类似 Kafka

  • 消息确认:支持 XACK 确认机制,防止消息丢失

  • 阻塞读取:支持阻塞式读取新消息

常用命令

XADDXREADXREADGROUPXACKXINFO

实际业务场景

① 订单处理流水线:保证订单不丢失、可追溯

复制代码
# 生产者:添加订单消息
XADD orders:* order_id 1001 user_id 2001 status "created"
# 消费者组:消费者1读取并处理
XREADGROUP GROUP order_workers consumer1 COUNT 1 STREAMS orders >

键命名规范:使用冒号分隔,如 业务名:表名:主键,例如 article:info:1001

警惕大Key:Hash 的 Field 过多、List 过长、ZSet 成员过多都可能导致 Redis 阻塞

选型优先原则:先用最匹配业务模型的数据结构,不要为了"省事"全用 String

内存与精度权衡:Bitmap 和 HyperLogLog 用极低内存解决特定问题,但要接受其局限性

总结

希望这篇文章能帮助你全面掌握 Redis 的九大数据结构,在实际项目中做出更优雅的设计选择。

相关推荐
2301_782659182 分钟前
MongoDB如果有一个分片完全宕机集群还能用吗_受影响数据的不可读与分片隔离感知
jvm·数据库·python
justjinji3 分钟前
JavaScript中严格模式use-strict对引擎解析的辅助
jvm·数据库·python
Absurd5875 分钟前
CSS如何使用-default获取默认选项样式_通过状态伪类突出预选表单项
jvm·数据库·python
风吹迎面入袖凉10 分钟前
【Redis】Redis缓存击穿
数据库·redis·缓存
weixin_4585801213 分钟前
CSS如何让flex布局支持老版本浏览器_添加-webkit-前缀与兼容性写法
jvm·数据库·python
Shorasul18 分钟前
CSS viewport单位在旧移动端支持不佳_利用固定像素值与rem配合
jvm·数据库·python
下地种菜小叶19 分钟前
定时任务系统怎么设计?一次讲清任务注册、分布式调度、幂等执行与失败补偿
java·开发语言·数据库·oracle·rabbitmq
z44247532620 分钟前
CSS如何实现响应式布局_使用Flexbox与Grid提升适配效率
jvm·数据库·python
Absurd58728 分钟前
优化文本分类中堆叠模型的网格搜索性能:避免训练卡顿的实用指南
jvm·数据库·python
2301_8152795228 分钟前
怎样通过Navicat高效导出ER模型为PDF文档_大幅提升绘制效率
jvm·数据库·python