Redis 在生产项目的使用

Redis 在生产项目里不要只当"快的 Map"用,要按场景、数据一致性、故障风险来设计。常见用法可以这样落地。

1. 最常见:缓存

典型流程:

rust 复制代码
请求 -> 查 Redis -> 命中直接返回
             -> 未命中查数据库
             -> 写入 Redis
             -> 返回结果

适合缓存:

  • 用户信息
  • 商品详情
  • 配置信息
  • 首页数据
  • 字典表
  • 权限信息
  • 热门内容

示例:

ini 复制代码
String key = "user:" + userId;
String json = redis.get(key);

if (json != null) {
    return JSON.parseObject(json, UserDTO.class);
}

User user = userMapper.selectById(userId);
if (user == null) {
    redis.setex(key, 60, ""); // 防缓存穿透,缓存空值
    return null;
}

redis.setex(key, 3600 + randomSeconds, JSON.toJSONString(user));
return user;

生产建议:

  • Key 必须有统一命名规范,例如 业务:对象:ID
  • 缓存对象要设置过期时间
  • 过期时间加随机值,避免雪崩
  • 空结果也可以短时间缓存
  • 大对象不要直接塞 Redis
  • 不要用 KEYS *,生产用 SCAN

2. 缓存更新策略

生产中最常用的是:

复制代码
先更新数据库,再删除缓存

例如:

sql 复制代码
更新用户信息:
1. update mysql user set ...
2. delete redis key user:123

为什么不是直接更新缓存?

因为缓存可能有复杂结构,直接更新容易出现脏数据。删除缓存后,下一次读取会重新从数据库加载。

常见策略:

复制代码
读:先查 Redis,未命中查 DB,再写 Redis
写:先写 DB,再删 Redis

更稳一点可以做:

rust 复制代码
写 DB -> 删缓存 -> 延迟几百毫秒再删一次

适合对一致性要求较高的场景。

注意:Redis 缓存通常只能做到最终一致,不适合作为强一致数据源。

3. 分布式锁

在多实例部署时,本地锁失效,这时可以用 Redis 分布式锁。

常见场景:

  • 防止重复下单
  • 防止定时任务多实例重复执行
  • 秒杀库存扣减
  • 同一个资源只允许一个服务处理
  • 防止缓存击穿时多个线程同时查数据库

基本命令:

sql 复制代码
SET lock:order:123 uuid NX EX 30

含义:

  • NX:不存在才设置
  • EX 30:30 秒后自动过期
  • uuid:锁持有者标识

释放锁必须校验 value:

vbnet 复制代码
if redis.call("get", KEYS[1]) == ARGV[1] then
  return redis.call("del", KEYS[1])
else
  return 0
end

生产建议:

  • 不要用 SETNX 后再单独 EXPIRE,非原子
  • 锁必须有过期时间
  • value 必须唯一
  • 释放锁必须用 Lua 校验
  • 业务时间可能超过锁过期时间时,要考虑续期
  • Java 项目可以直接用 Redisson

4. 计数器

Redis 很适合做高并发计数。

场景:

  • 浏览量
  • 点赞数
  • 收藏数
  • 登录失败次数
  • 接口调用次数

例如文章浏览量:

css 复制代码
INCR article:1001:view_count

生产上通常不要每次都同步写数据库,可以:

复制代码
先写 Redis 计数
定时任务批量同步到 MySQL

这样可以减少数据库压力。

5. 限流

Redis 可以做接口限流。

例如:用户 1 分钟最多请求 100 次。

sql 复制代码
INCR rate:user:123
EXPIRE rate:user:123 60

伪代码:

ini 复制代码
String key = "rate:user:" + userId + ":" + currentMinute;
Long count = redis.incr(key);
if (count == 1) {
    redis.expire(key, 60);
}
if (count > 100) {
    throw new TooManyRequestsException();
}

生产建议:

  • 简单限流用固定窗口
  • 精准限流用滑动窗口或令牌桶
  • 高要求场景建议 Lua 脚本保证原子性

6. 排行榜

ZSet

场景:

  • 用户积分榜
  • 热门文章榜
  • 游戏排行榜
  • 销量榜
less 复制代码
ZINCRBY rank:article:daily 1 article:1001
ZREVRANGE rank:article:daily 0 9 WITHSCORES

生产建议:

  • 按天、周、月拆 key
  • 定期删除历史排行榜
  • 大榜单只取 Top N,不要全量拉取
  • 需要持久化的榜单定期落库

7. 会话和 Token

如果是多实例服务,Session 不能只存在单机内存里,可以放 Redis。

场景:

  • 登录态
  • Token 黑名单
  • 验证码
  • 短信验证码
  • 临时授权码

例如验证码:

less 复制代码
SETEX sms:code:13800138000 300 123456

生产建议:

  • 设置短 TTL
  • Key 里不要直接暴露敏感信息,必要时 hash 手机号
  • 验证成功后立即删除
  • 验证失败次数也要限制

8. 消息队列

Redis 可以做轻量消息队列,但要看场景。

简单队列:

arduino 复制代码
LPUSH queue:order msg
BRPOP queue:order 5

更推荐 Redis Stream:

lua 复制代码
XADD order_stream * orderId 1001 status paid
XREADGROUP GROUP g1 c1 COUNT 10 STREAMS order_stream >

适合:

  • 异步任务
  • 低成本事件流
  • 简单业务解耦

但如果是核心交易链路,通常优先 Kafka、RabbitMQ、RocketMQ,因为它们在消息堆积、重试、路由、可观测性方面更成熟。

9. 延迟任务

可以用 ZSet 实现。

sql 复制代码
ZADD delay:order 1718880000 order:1001

消费者定时扫描:

arduino 复制代码
ZRANGEBYSCORE delay:order 0 now LIMIT 0 100

取到后处理,再删除。

场景:

  • 订单超时关闭
  • 延迟通知
  • 自动取消任务

生产注意:

  • 要防止多个消费者重复处理
  • 删除任务和处理任务要设计幂等
  • 数据量很大时建议用专门的延迟队列组件

10. 防缓存击穿

热点 Key 过期时,大量请求可能同时打到数据库。

解决方式:

bash 复制代码
查 Redis 未命中
尝试获取锁
  拿到锁:查 DB,写 Redis
  没拿到锁:短暂 sleep 后重试 Redis

伪流程:

csharp 复制代码
get cache
if hit return

lock = tryLock("lock:user:1")
if lock:
    query db
    set cache
    unlock
else:
    sleep 50ms
    retry cache

热点数据也可以使用:

  • 永不过期
  • 逻辑过期
  • 后台异步刷新

11. Key 设计规范

推荐格式:

makefile 复制代码
系统:业务:对象:ID:字段

示例:

vbnet 复制代码
mall:user:1001
mall:product:sku:2001
mall:cart:user:1001
mall:rank:article:daily:20260620
mall:lock:order:1001
mall:rate:user:1001:202606201530

规范建议:

  • 使用冒号分隔
  • 避免过长 key
  • 避免特殊字符
  • 不要把整个 JSON 当 key
  • 明确 TTL 规则
  • 大 key 要拆分

12. 生产配置重点

一定要关注:

  • maxmemory
  • maxmemory-policy
  • 持久化策略
  • 慢查询日志
  • 连接数
  • 客户端连接池
  • 主从复制延迟
  • Redis Cluster 分片
  • 哨兵高可用
  • 监控和告警

缓存型 Redis 常见:

复制代码
maxmemory-policy allkeys-lru

更安全的通用策略:

arduino 复制代码
maxmemory-policy volatile-lru

前提是重要缓存都设置 TTL。

13. 生产不要这样用

尽量避免:

  • 用 Redis 当唯一数据库,除非你非常清楚持久化和恢复风险
  • 生产环境执行 KEYS *
  • 存超大 value,比如几 MB 的 JSON
  • 一个 Hash/List/Set/ZSet 里塞几百万元素
  • 不设置 TTL 导致内存无限增长
  • 分布式锁不设置过期时间
  • 直接删除锁,不校验 value
  • 把 Redis 用成核心消息系统却没有补偿机制
  • 缓存和数据库一致性没有设计

14. 一个典型生产用法组合

例如电商商品详情页:

markdown 复制代码
商品详情:
1. 查 Redis:mall:product:detail:skuId
2. 命中直接返回
3. 未命中查 MySQL
4. 空数据缓存 1 分钟
5. 正常数据缓存 30 分钟 + 随机秒数
6. 更新商品时:先更新 MySQL,再删除 Redis
7. 热门商品用逻辑过期 + 后台刷新
8. 浏览量用 Redis INCR,定时批量落库
9. 商品排行榜用 ZSet
10. 下单防重复用 Redis 分布式锁或数据库唯一约束

一句话总结:

Redis 在生产项目里主要承担三类角色:缓存加速、分布式协调、实时数据结构计算 。真正要用好 Redis,关键不是会 GET/SET,而是要设计好 Key、TTL、一致性、故障降级、监控和数据恢复策略

相关推荐
用户559822481221 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode1 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战1 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
风骏时光牛马1 小时前
# Ruby基于Rails框架实现多角色权限管理与数据分页查询完整实战代码案例
前端
weedsfly1 小时前
迭代器、生成器与异步迭代——让数据“按需流动”的艺术
前端·javascript
xiaodaoluanzha1 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn1 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
Csvn1 小时前
Fetch 请求竞态终结者:AbortController 不只是用来"取消"的
前端
阡陌Jony1 小时前
关于前端路由中的参数问题的学习(一): params,query, hash(#)
前端