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 的九大数据结构,在实际项目中做出更优雅的设计选择。

相关推荐
Boop_wu2 小时前
[Java 算法] 快速排序和快速选择排序(※)
数据结构·算法·排序算法
七度黑光10 小时前
用 openclaw 给故障复盘打分:质量审核自动化实践
运维·服务器·前端·数据库·自动化
华科易迅12 小时前
Spring 事务(注解)
java·数据库·spring
Java面试题总结12 小时前
MySQL篇 索引失效
数据库·mysql
last demo12 小时前
mysql
运维·数据库·mysql·oracle
皙然13 小时前
Redis配置文件(redis.conf)超详细详解
前端·redis·bootstrap
indexsunny13 小时前
互联网大厂Java面试实战:从Spring Boot到微服务的技术问答解析
java·spring boot·redis·微服务·消息队列·电商
kevin_cat14 小时前
oracle 扩展表空间
数据库·oracle
paeamecium14 小时前
【PAT甲级真题】- Student List for Course (25)
数据结构·c++·算法·list·pat考试