Redis 之所以能成为高性能缓存与实时计算的"瑞士军刀",核心在于其丰富的数据结构。本文系统梳理 Redis 九大核心数据类型,从底层实现到生产级应用场景,帮你建立完整的选型决策框架。
一、基础数据类型(五大金刚)
1. String(字符串)
String 是 Redis 最基础、最常用的数据类型,二进制安全,可存储文本、数字、图片 Base64、序列化对象等任意数据,最大支持 512MB 。
底层实现:采用 SDS(Simple Dynamic String,简单动态字符串)替代 C 原生字符串,获取长度时间复杂度为 O(1),且 API 安全不会造成缓冲区溢出 。
核心应用场景:
| 场景 | 说明 | 关键命令 |
|---|---|---|
| 缓存对象 | 存储用户信息、Token、图片地址等,支持 TTL 自动过期 | SET、GET、MSET |
| 原子计数器 | 阅读量、点赞数、库存扣减(利用单线程原子性) | INCR、DECR、INCRBY |
| 分布式锁 | SETNX key value 实现简易锁,配合 PX 过期时间防止死锁 |
SET key value NX PX 10000 |
生产建议:缓存对象时,若对象属性频繁变化,建议用 Hash 替代 String + JSON,减少网络传输和序列化开销 。
2. Hash(哈希)
Hash 是键值对集合,结构为 key → {field: value, ...},天然适合存储对象型数据 。
底层实现:元素较少时用 ziplist(压缩列表)节省内存,元素增多后自动转为 hashtable,保证 O(1) 字段访问 。
核心应用场景:
| 场景 | 设计模式 | 命令示例 |
|---|---|---|
| 对象缓存 | 用户 ID 为 key,属性为 field | HSET user:1001 name "Tom" age 20 |
| 购物车 | 用户 ID 为 key,商品 ID 为 field,数量为 value | HINCRBY cart:user1 1001 2 |
| 动态配置 | 配置项分类为 key,具体参数为 field | HSET config:db host "127.0.0.1" |
与 String 的对比:Hash 支持字段级原子操作,修改单个属性无需读取整个对象,网络流量更省 。
3. List(列表)
List 是双向链表结构,支持从两端高效插入和弹出,天然具备队列特性 。
底层实现:Redis 3.2 后采用 quicklist(ziplist 链表),兼顾内存紧凑和插入效率 。
核心应用场景:
| 场景 | 模式 | 命令组合 |
|---|---|---|
| 消息队列 | 生产者 LPUSH,消费者 BRPOP 阻塞消费 | LPUSH queue msg / BRPOP queue 30 |
| 最新消息流 | 固定长度列表,自动淘汰旧数据 | LPUSH timeline msg + LTRIM timeline 0 99 |
| 异步任务队列 | 任务入队,工作进程出队处理 | RPUSH tasks task_id / LPOP tasks |
⚠️ List 做消息队列的局限:无内置消息 ID 生成、不支持消费组模式。若需复杂队列能力,建议使用 Redis 5.0 引入的 Stream 类型 。
4. Set(集合)
Set 是无序、不重复的元素集合,底层基于 intset(纯整数)或 hashtable 实现,元素存在性检测时间复杂度 O(1) 。
核心应用场景:
| 场景 | 业务价值 | 关键命令 |
|---|---|---|
| 去重统计 | 文章点赞用户、UV 统计(数据量巨大时建议用 HyperLogLog) | SADD、SCARD、SISMEMBER |
| 社交关系 | 共同好友(交集)、好友推荐(差集)、共同关注 | SINTER、SDIFF、SUNION |
| 随机抽奖 | 无重复中奖用 SPOP,允许重复用 SRANDMEMBER |
SPOP prizes 3 |
Set 的集合运算在服务端完成,避免了客户端拉取大量数据后的内存计算,是社交类应用的核心利器 。
5. Sorted Set(有序集合 / ZSet)
ZSet 是 Set 的增强版,每个元素关联一个 score(分数),按 score 自动排序。底层采用跳表(skiplist)+ 哈希表组合结构:跳表保障范围查询效率 O(logN),哈希表保障单点查询 O(1) 。
核心应用场景:
| 场景 | 设计要点 | 命令示例 |
|---|---|---|
| 排行榜 | 分数实时变动,支持快速排名查询 | ZINCRBY leaderboard 10 "playerA" |
| 延时队列 | score 为执行时间戳,定期轮询到期任务 | ZADD delay_queue 1715836800 "task_id" |
| 滑动窗口限流 | score 为时间戳,移除窗口外元素 | ZREMRANGEBYSCORE |
| 热门搜索 | 搜索词为 member,搜索次数为 score | ZINCRBY hot_search 1 "关键词" |
ZSet 的 ZRANGEBYSCORE 支持按分数范围分页查询,是构建实时榜单系统的首选数据结构 。
二、高阶数据类型(四大神器)
6. Bitmap(位图)
Bitmap 本质上是 String 类型的位操作扩展,将每个 bit 作为独立标记位,时间复杂度 O(1),内存效率极高(1 亿用户在线状态仅需约 12MB)。
核心应用场景:
| 场景 | 设计模式 | 命令 |
|---|---|---|
| 签到统计 | 每个用户一个 key,偏移量对应日期,1 表示已签到 | SETBIT sign:user:1001 15 1 |
| 用户在线状态 | 用户 ID 为偏移量,1 在线 0 离线 | SETBIT online 1001 1 |
| 连续签到奖励 | 通过 BITPOS 查找首次打卡位置,结合 BITCOUNT 统计天数 |
BITCOUNT sign:user:1001 |
Bitmap 仅适合二值状态(0/1),若需存储多状态需考虑其他方案 。
7. HyperLogLog
HyperLogLog 是概率型基数统计结构,标准误差率 0.81%,但无论统计多少元素,固定仅需 12KB 内存 。
核心应用场景:
- 百万级 UV 统计:网页独立访客、广告曝光去重计数
- 海量数据去重:用户行为日志的去重分析
命令示例:
bash
PFADD visitors 192.168.1.1 192.168.1.2
PFCOUNT visitors # 返回估算 UV 值
⚠️ 注意:HyperLogLog 只支持基数估算,无法获取具体元素列表。若需精确去重,仍需使用 Set 或 Hash 。
8. GEO(地理空间)
GEO 基于 Sorted Set 实现,使用 GeoHash 编码将二维经纬度转换为一维 score,从而复用 ZSet 的有序范围查询能力 。
核心应用场景:
| 场景 | 命令示例 |
|---|---|
| 附近的人/门店 | GEORADIUS users 116.40 39.90 5 km WITHDIST |
| 距离计算 | GEODIST store:1 store:2 km |
| 地理位置索引 | GEOADD stores 116.397 39.916 "BeijingStore" |
GEO 的 GEORADIUS 查询时间复杂度 O(logN),性能远超关系型数据库的空间索引 。
9. Stream(流)
Stream 是 Redis 5.0 引入的日志型数据结构,专为消息队列场景设计,底层基于 Rax 基数树 。
相比 List 的核心增强:
| 特性 | List | Stream |
|---|---|---|
| 消息 ID | 需自行生成 | 自动生成全局唯一时间戳 ID |
| 消费模式 | 单消费者 | 支持消费者组(Consumer Group) |
| 消息确认 | 无 | 支持 ACK 机制,确保消息至少被消费一次 |
| 消息持久化 | 弹出即丢失 | 可保留历史消息,支持范围读取 |
核心应用场景:
- 实时日志采集:应用日志、物联网设备数据流
- 可靠消息队列:需要消费组竞争消费、故障转移的业务场景
- 事件溯源(Event Sourcing):保留完整操作历史,支持回放
bash
XADD orders * productID 1001 userID 5566 # 生产者
XREADGROUP GROUP consumers consumer-1 COUNT 1 STREAMS orders > # 消费者组读取
XACK orders 1715836800000-0 # 确认消费
Stream 在轻量级队列场景下部署成本远低于 Kafka,但海量消息积压场景仍建议选用专业消息队列 。
三、选型决策速查表
| 业务需求 | 推荐类型 | 关键考量 |
|---|---|---|
| 简单缓存 / 计数 / 分布式锁 | String | 原子操作、TTL 支持 |
| 对象属性频繁更新 | Hash | 字段级操作、节省网络流量 |
| 简单队列 / 时间线 | List | 双向操作、阻塞消费 |
| 去重 / 社交关系运算 | Set | 交集差集并集原生支持 |
| 排行榜 / 范围查询 / 延时队列 | ZSet | 自动排序、范围查询 O(logN) |
| 二值状态(签到、在线) | Bitmap | 极致内存效率 |
| 海量 UV / 基数统计 | HyperLogLog | 固定 12KB 内存 |
| 地理位置 / 附近搜索 | GEO | GeoHash 编码、距离计算 |
| 可靠消息队列 / 日志流 | Stream | 消费者组、ACK 机制 |
四、总结
Redis 的数据结构设计体现了**"针对不同场景提供最优解"**的哲学。基础五类型覆盖了 80% 的日常需求,而 Bitmap、HyperLogLog、GEO、Stream 则在特定领域提供了数量级上的性能或空间优化。
在实际选型时,建议遵循两个原则:
- 数据特征匹配:二值状态用 Bitmap,排序需求用 ZSet,地理位置用 GEO
- 规模预判:数据量小用基础类型即可,海量数据优先考虑 HyperLogLog、Bitmap 等压缩结构
理解每种类型的底层实现(如 ZSet 的跳表+哈希表、Stream 的 Rax 树),能帮助你在面对复杂业务需求时做出更精准的架构决策 。