目录
[Redis 数据结构](#Redis 数据结构)
[Sorted Set(有序集合,ZSet)](#Sorted Set(有序集合,ZSet))
前言
提到 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 系列命令保证高并发下的计数准确
常用命令
SET、GET、MSET、MGET、INCR、DECR、SETNX
实际业务场景
① 常规缓存:存储 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)
常用命令
HSET、HGET、HGETALL、HINCRBY、HDEL、HEXISTS
实际业务场景
① 购物车:以用户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(双向链表 + 压缩列表)结构,兼顾内存效率和访问速度
常用命令
LPUSH、RPUSH、LPOP、RPOP、LRANGE、BLPOP、BRPOP
实际业务场景
① 轻量级消息队列:利用 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 命令效率极高
常用命令
SADD、SREM、SMEMBERS、SISMEMBER、SINTER、SUNION
实际业务场景
① 标签系统:给文章打标签,或给用户打兴趣标签
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 可以是整数或双精度浮点数
底层实现:跳表 + 哈希表,兼顾排序和快速查找
常用命令
ZADD、ZRANGE、ZREVRANGE、ZINCRBY、ZRANK、ZRANGEBYSCORE
实际业务场景
① 排行榜:这是 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 两种状态的场景
常用命令
SETBIT、GETBIT、BITCOUNT、BITOP、BITPOS
实际业务场景
① 用户签到:以用户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
常用命令
PFADD、PFCOUNT、PFMERGE
实际业务场景
① 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 实现的,专门用于存储地理位置(经纬度)和计算距离。
特点
位置存储:存储经度、纬度,支持名称关联
距离计算:支持计算两点之间的直线距离
范围查询:支持查找指定半径内的所有位置
常用命令
GEOADD、GEODIST、GEORADIUS、GEORADIUSBYMEMBER
实际业务场景
① 附近的人/店铺:基于位置推荐附近商家
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 确认机制,防止消息丢失
阻塞读取:支持阻塞式读取新消息
常用命令
XADD、XREAD、XREADGROUP、XACK、XINFO
实际业务场景
① 订单处理流水线:保证订单不丢失、可追溯
# 生产者:添加订单消息
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 的九大数据结构,在实际项目中做出更优雅的设计选择。