Redis 从零到精通:9大数据结构 × 11个高频工程实战场景完全手册

覆盖 String/Hash/List/Set/ZSet/Bitmap/HyperLogLog/Geo/Stream 全数据结构,秒杀、限流、延迟队列、分布式会话、分布式ID、购物车等11个真实场景代码逐行解析。


一、入门:会用 Redis

1. Redis 是什么

Redis 是一个基于内存的高性能 Key-Value 数据库。它不仅能存字符串,还支持多种数据结构,常用于缓存、计数器、排行榜、分布式锁、消息队列、会话存储和实时统计。

Redis 的主要特点:

  • 基于内存,读写性能高。
  • 支持 String、Hash、List、Set、ZSet、Stream 等数据结构。
  • 支持过期时间,适合做缓存。
  • 支持 RDB 和 AOF 持久化。
  • 支持主从复制、Sentinel 和 Cluster。
  • 命令执行模型简单,单条命令具备原子性。

典型使用场景:

场景 常用数据结构 示例
缓存用户信息 String / Hash user:1001
验证码 String verify:phone:138xxxx
文章阅读量 String article:1001:views
抽奖 Set lottery:users
排行榜 ZSet game:rank
消息队列 List / Stream order:stream
分布式锁 String lock:order:1001

2. Key 基础命令

常用命令
bash 复制代码
SET name redis
GET name

EXISTS name
DEL name

EXPIRE name 60
TTL name

TYPE name
SCAN 0
示例:设置验证码
bash 复制代码
SET verify:1001 9527 EX 60
GET verify:1001
TTL verify:1001

说明:

  • EX 60 表示 60 秒后过期。
  • TTL 查看剩余过期时间。

生产环境注意:

bash 复制代码
KEYS *

KEYS * 会遍历所有 key,可能阻塞 Redis。生产环境建议使用:

bash 复制代码
SCAN 0 MATCH user:* COUNT 100

二、Redis 全数据结构详解

1. String:字符串

String 是 Redis 最基础的数据结构,可以存普通字符串、数字、JSON 字符串、二进制内容。

基础命令
bash 复制代码
SET user:1:name Tom
GET user:1:name

MSET user:1:name Tom user:1:age 20
MGET user:1:name user:1:age

INCR article:1001:views
INCRBY article:1001:views 10
DECR stock:1001
示例:缓存用户 JSON
bash 复制代码
SET user:1 '{"id":1,"name":"Tom","age":20}' EX 300
GET user:1

适合场景:验证码 / Token / Session / 页面缓存 / 对象 JSON 缓存 / 计数器


2. Hash:哈希

Hash 适合存对象,可以单独读写对象中的某个字段。

基础命令
bash 复制代码
HSET user:1 name Tom age 20 city Shanghai
HGET user:1 name
HMGET user:1 name age
HGETALL user:1
HINCRBY user:1 age 1
HDEL user:1 city
示例:购物车
bash 复制代码
HSET cart:1001 product:2001 2
HSET cart:1001 product:2002 1
HINCRBY cart:1001 product:2001 1
HGETALL cart:1001
String JSON 与 Hash 对比
方案 优点 缺点
String 存 JSON 读取整体对象方便 修改单个字段需要反序列化再写回
Hash 可单独修改字段 对复杂嵌套对象不如 JSON 直观

3. List:列表

List 是有序、可重复的链表结构,适合做队列、栈、最近记录。

基础命令
bash 复制代码
LPUSH queue task1
RPOP queue
BRPOP order:queue 10
LRANGE logs 0 9

适合场景:简单消息队列 / 最近浏览记录 / 操作日志 / 栈结构

局限:消息确认机制弱,更可靠的队列建议使用 Stream 或专业 MQ。


4. Set:集合

Set 是无序、不可重复的集合,适合去重和集合运算。

基础命令
bash 复制代码
SADD user:1:tags java redis mysql
SMEMBERS user:1:tags
SISMEMBER user:1:tags redis
SCARD user:1:tags
集合运算
bash 复制代码
SINTER user:1:follows user:2:follows   # 共同好友
SUNION user:1:follows user:2:follows   # 所有好友
SDIFF user:1:follows user:2:follows    # 独有好友
示例:抽奖
bash 复制代码
SADD lottery:users 1001 1002 1003 1004
SRANDMEMBER lottery:users 2   # 不移除
SPOP lottery:users 1           # 移除

5. ZSet:有序集合

ZSet 是有序集合,每个元素都有一个分数,Redis 按分数排序。

示例:游戏排行榜
bash 复制代码
ZADD game:rank 1200 user:1001
ZADD game:rank 1800 user:1002
ZADD game:rank 1500 user:1003

ZREVRANGE game:rank 0 9 WITHSCORES    # TOP 10
ZREVRANK game:rank user:1001           # 查名次
ZINCRBY game:rank 50 user:1001         # 加分

适合场景:排行榜 / 热门文章 / 延迟队列 / 时间线


6. Bitmap:位图

Bitmap 本质上是 String 的位操作,极节省内存。1亿用户签到状态只需约 12MB。

基础命令
bash 复制代码
SETBIT key offset value
GETBIT key offset
BITCOUNT key [start end]
BITOP AND|OR|XOR|NOT destkey key [key ...]
示例:用户签到
bash 复制代码
# 用户 1001 在 2026年4月 第 24 天签到
SETBIT sign:1001:202604 23 1

# 查询是否签到
GETBIT sign:1001:202604 23

# 统计当月签到天数
BITCOUNT sign:1001:202604
集合运算
bash 复制代码
# 求两天都签到的用户(AND)
BITOP AND result:and sign:20260423 sign:20260424

适合场景:签到打卡 / 在线状态 / 功能开关 / 布隆过滤器底层


7. HyperLogLog:基数估算

HyperLogLog 用于统计不重复元素数量,误差约 0.81%,每个 key 固定占用约 12KB 内存。

示例:UV 统计
bash 复制代码
PFADD uv:20260424 user:1001 user:1002 user:1003 user:1001
PFCOUNT uv:20260424

# 合并多天数据,统计周 UV
PFMERGE uv:week uv:20260418 uv:20260419 uv:20260420 uv:20260421 uv:20260422 uv:20260423 uv:20260424
PFCOUNT uv:week
方案 精确性 内存占用 适合场景
Set 精确 随数据增长 需要知道具体是哪些用户
HyperLogLog 约 0.81% 误差 约 12KB 固定 只关心数量,不关心是谁

8. Geo:地理位置

Geo 基于 ZSet 实现,支持附近搜索和距离计算。

示例:附近门店
bash 复制代码
GEOADD stores 121.4737 31.2304 "shop:1001"
GEOADD stores 121.4800 31.2350 "shop:1002"

# 查询 5km 内的门店,按距离排序
GEOSEARCH stores FROMLONLAT 121.4737 31.2304 BYRADIUS 5 km ASC COUNT 10

# 计算两店距离
GEODIST stores shop:1001 shop:1002 km

适合场景:附近的人 / 附近门店 / 配送范围 / 地理围栏


9. Stream:消息队列

Stream 是 Redis 提供的日志型消息结构,更适合做消息队列。

bash 复制代码
# 生产消息
XADD order:stream * orderId 1001 userId 1

# 创建消费者组
XGROUP CREATE order:stream group1 0 MKSTREAM

# 消费
XREADGROUP GROUP group1 consumer1 COUNT 1 STREAMS order:stream >

# 确认
XACK order:stream group1 message-id
方案 是否持久化 是否支持消费者组 是否适合可靠队列
Pub/Sub 不适合
List 部分支持 一般
Stream 较适合

三、提高:缓存设计与工程实践

1. Cache Aside 缓存模式

读流程:

text 复制代码
查询缓存
  -> 命中:直接返回
  -> 未命中:查询数据库
      -> 写入缓存
      -> 返回结果

写流程(推荐):

java 复制代码
mysql.update(user);
redis.del("user:" + user.getId());

不推荐"更新数据库后更新缓存",因为多个并发写操作可能导致缓存中出现旧值。


2. 缓存穿透

问题: 请求的数据既不在 Redis,也不在数据库。

解决方案一:缓存空值

bash 复制代码
SET user:999999 null EX 60

解决方案二:布隆过滤器

text 复制代码
请求 user:999999999
  -> 布隆过滤器判断一定不存在
  -> 直接拒绝

3. 缓存击穿

问题: 某个热点 Key 过期,大量请求同时打到数据库。

解决方案一:互斥锁

bash 复制代码
SET lock:rebuild:product:1001 1 NX EX 10

解决方案二:逻辑过期

缓存中保存逻辑过期时间,过期后先返回旧数据,后台异步刷新。


4. 缓存雪崩

问题: 大量 Key 同时过期,或 Redis 整体不可用。

解决: TTL 加随机值 + 热点数据预热 + 多级缓存 + 限流降级

java 复制代码
int ttl = 300 + random.nextInt(60);
redis.set(key, value, ttl);

5. 缓存预热

应用启动前主动加载热点数据:

java 复制代码
@Component
public class CacheWarmup implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) {
        List<Product> hotProducts = productMapper.selectHotProducts();
        for (Product p : hotProducts) {
            redis.set("product:detail:" + p.getId(), toJson(p), 300 + random.nextInt(60));
        }
    }
}
风险 应对
启动雷暴 分批预热、主从只由主实例预热
内存超限 只预热访问频率最高的 Top N
数据过期 合理 TTL + 随机偏移

6. 分布式锁

bash 复制代码
SET lock:order:1001 requestId NX EX 10

安全释放(Lua 脚本):

lua 复制代码
if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end

工程实践中常用 Redisson,提供锁续期(看门狗)、可重入锁、公平锁、读写锁等能力。


7. Lua 脚本

Lua 脚本可以让多条 Redis 命令原子执行。

示例:限流脚本

lua 复制代码
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local expire = tonumber(ARGV[2])

local count = redis.call("INCR", key)

if count == 1 then
    redis.call("EXPIRE", key, expire)
end

if count > limit then
    return 0
else
    return 1
end

8. Pipeline

Pipeline 用于批量发送命令,减少网络往返次数。

java 复制代码
Pipeline pipeline = jedis.pipelined();
for (int i = 0; i < 1000; i++) {
    pipeline.set("key:" + i, "value:" + i);
}
pipeline.sync();

四、典型工程实例

1. 秒杀库存扣减(Lua 防超卖)

lua 复制代码
local stockKey = KEYS[1]
local orderKey = KEYS[2]
local userId = ARGV[1]

if redis.call("SISMEMBER", orderKey, userId) == 1 then
    return 2   -- 重复下单
end

local stock = tonumber(redis.call("GET", stockKey))
if stock <= 0 then
    return 0   -- 库存不足
end

redis.call("DECR", stockKey)
redis.call("SADD", orderKey, userId)
return 1       -- 抢购成功

完整流程:

text 复制代码
用户请求
  -> Redis Lua 判断库存和重复下单
  -> 扣减 Redis 库存
  -> 写入消息队列
  -> 异步创建订单
  -> 数据库最终落库

2. 接口限流

固定窗口限流:

bash 复制代码
INCR rate:user:1001
EXPIRE rate:user:1001 60

滑动窗口限流(ZSet):

bash 复制代码
ZADD rate:user:1001 1713931200000 request-1
ZREMRANGEBYSCORE rate:user:1001 0 1713931140000
ZCARD rate:user:1001

3. 延迟队列

使用 ZSet,score 为执行时间戳:

bash 复制代码
# 添加任务
ZADD delay:queue 1713931200000 order:1001

# 拉取到期任务
ZRANGEBYSCORE delay:queue 0 1713931200000 LIMIT 0 10

# 删除已处理任务
ZREM delay:queue order:1001

适合:订单超时取消 / 延迟通知 / 失败重试


4. 商品详情缓存

java 复制代码
String key = "product:detail:" + productId;
String cache = redis.get(key);

if (cache != null) {
    return parse(cache);
}

Product product = productMapper.selectById(productId);

if (product == null) {
    redis.set(key, "null", 60);   // 防穿透:缓存空值
    return null;
}

int ttl = 300 + random.nextInt(60);   // 防雪崩:随机 TTL
redis.set(key, toJson(product), ttl);
return product;

5. 分布式会话

bash 复制代码
HSET session:abc123 userId 1001 username Tom role admin loginTime 1713931200
EXPIRE session:abc123 1800
HGETALL session:abc123

Token 方案对比:

方案 存储位置 特点
Session + Redis 服务端 Redis 服务端可控,支持主动注销
JWT 客户端 Token 无需服务端存储,但无法主动失效
JWT + Redis 黑名单 客户端 + Redis 兼顾无状态和主动注销

Spring Boot 集成:

yaml 复制代码
spring:
  session:
    store-type: redis
    timeout: 30m

6. 分布式 ID 生成

bash 复制代码
INCR order:id
INCRBY order:id:segment 1000   # 号段模式,一次取 1000 个
方案 有序性 性能 风险
Redis INCR 严格递增 Redis 宕机影响
Redis 号段 段内递增 极高 段用完前 Redis 宕机可暂用
Snowflake 趋势递增 极高 时钟回拨

本文是《Redis 知识体系》系列第一篇,覆盖数据结构与高频工程实战。
第二篇:《Redis 原理深度解析》→ 持久化/主从/Sentinel/Cluster/性能排查
第三篇:《Redis 专家实战》→ 生产架构/容量规划/安全/37道面试题

相关推荐
qiuyunoqy1 小时前
MySQL - 2
数据库·mysql
2301_775148151 小时前
如何授权AWR报告生成_GRANT SELECT ANY DICTIONARY诊断权限
jvm·数据库·python
空中海2 小时前
Redis 专家实战:生产架构设计 × 容量规划 × 安全治理 × 37道高频面试题全解
数据库·redis·安全
地球资源数据云2 小时前
1951-2025年中国逐年1千米逐月总降水量区域统计数据集_年表_县
大数据·数据结构·数据库·数据仓库·人工智能
l1t2 小时前
DeepSeek v4辅助生成的单文件SQL查询示例页面
javascript·数据库·sql
云飞云共享云桌面2 小时前
精密机械制造工厂研发部门使用SolidWorks和ug,三维设计云桌面如何选择?
大数据·运维·服务器·网络·数据库·人工智能·制造
IntMainJhy3 小时前
【flutter for open harmony】第三方库 Flutter 二维码生成的鸿蒙化适配与实战指南
数据库·flutter·华为·sqlite·harmonyos
それども3 小时前
Spring Bean 注入的优先级顺序
java·数据库·sql·spring
张子行的博客3 小时前
SQL 调优实战:跨表排序性能提升之路
数据库·sql·oracle