Appearance
Redis 在后端项目里的高频场景:缓存、分布式锁、防重与会话共享
很多项目把 Redis 用上了,但真正出问题时,往往不是“不会连”,而是:
- 不知道什么数据适不适合放 Redis
- 不清楚缓存一致性边界
- 低估了分布式锁的实现细节
Redis 很强,但它不是数据库替代品,也不是所有一致性问题的万能解法。
先说结论
在后端项目里,Redis 最常见的价值主要有四类:
- 做缓存
- 做分布式锁
- 做防重和令牌校验
- 做会话或短期状态共享
真正把 Redis 用稳,关键不是记更多命令,而是把一致性边界和失效策略想清楚。
一、先分清本地缓存和分布式缓存
这一点看起来基础,但非常重要。
1. 本地缓存
缓存只存在当前服务实例内,例如:
- Caffeine
- Guava Cache
优点:
- 访问极快
- 没有网络开销
缺点:
- 多实例之间不共享
- 数据一致性更难控制
2. 分布式缓存
缓存放在 Redis 这类独立中间件里,多个服务实例共享同一份数据。
优点:
- 多实例可共享
- 更适合分布式部署
缺点:
- 有网络开销
- 需要额外考虑热点、过期、淘汰和故障恢复
二、场景一:缓存
这是 Redis 最常见的用法。
适合放到 Redis 的数据通常具备这些特点:
- 读多写少
- 查询代价相对高
- 可以接受短暂不一致
例如:
- 商品详情
- 配置项
- 热门列表
- 统计结果
缓存三类高频问题
1. 缓存穿透
查一个本来就不存在的数据,大量请求都打到数据库。
常见思路:
- 缓存空值并设置较短过期时间
- 布隆过滤器
- 接口层防刷
2. 缓存击穿
某个热点 Key 失效瞬间,大量请求同时回源数据库。
常见思路:
- 热点数据不过期
- 加互斥锁
- 预热缓存
3. 缓存雪崩
一批 Key 在同一时间大面积失效。
常见思路:
- 过期时间加随机值
- 热点数据错峰失效
- 服务限流与降级
- 做好缓存预热和主从高可用
三、缓存一致性怎么想更务实
很多人刚接触缓存时,容易把一致性要求想得过高。
但大部分缓存场景里,更现实的策略通常是:
- 写数据库
- 删除缓存
- 下一次读请求再回源重建缓存
这是最常见、也最容易落地的思路。
为什么不推荐把缓存一致性设计得太复杂
因为很多业务数据本来就允许短暂不一致,例如:
- 商品介绍
- 菜单配置
- 展示类列表
如果为了这类数据追求强一致,系统复杂度会很快上涨。
更实用的原则
- 对一致性要求极高的数据,优先查数据库
- 对允许短暂脏读的数据,缓存加过期时间通常已经够用
- 对热点写场景,再考虑延迟双删、订阅 binlog 或加读写锁
也就是说,不是缓存做不到强一致,而是很多时候没必要为此付出过高复杂度。
四、场景二:分布式锁
当服务已经是多实例部署时,本地锁只能锁住单个进程。
这时才会考虑 Redis 分布式锁。
最经典的思路是:
text
SET key value NX EX seconds重点不在“能不能加锁”,而在这些边界:
- 进程挂了怎么办
- 锁到期了但业务没执行完怎么办
- 删除锁时怎么保证删的是自己的锁
更稳妥的几个原则
- 锁一定要有过期时间
- value 里要带唯一标识
- 判断和删除要保证原子性
- 业务执行时间可能很长时,要考虑续期机制
为什么删除锁要原子
如果你先判断 value,再单独执行删除,中间可能发生:
- 锁过期
- 别的线程拿到新锁
这时你删掉的就不是自己的锁了。
所以更稳妥的方式通常是:
- 用 Lua 脚本把“判断 + 删除”放到一个原子操作里
Redisson 为什么常被推荐
因为它帮你把很多容易漏掉的细节封装掉了,例如:
- 可重入锁
- 看门狗续期
- 更完整的锁模型
看门狗续期可以怎么理解
如果锁默认只给一个固定过期时间,业务执行过长时就会出现:
- 锁提前过期
- 别的线程拿到锁
- 当前线程执行完又去删掉别人的锁
Redisson 的看门狗机制,本质上就是:
- 在业务线程还活着时,周期性给锁续命
它解决的不是所有一致性问题,而是“锁持有时间不可预估”这个很常见的工程问题。
五、场景三:防重和令牌校验
这类场景也很常见,例如:
- 表单重复提交
- 订单防重
- 短时间重复请求拦截
常见做法:
- 为请求生成唯一 token
- token 放入 Redis
- 校验成功后立即删除
这里的关键点同样是:
- 校验和删除尽量保证原子性
否则高并发下依然可能重复消费。
六、场景四:会话共享和短期状态
例如:
- 登录态共享
- 短信验证码
- 临时业务上下文
- 分布式限流计数
这类数据通常具备:
- 生命周期短
- 需要跨服务共享
Redis 非常适合承载这类状态。
七、Redis 很快,但不是强一致协调器
这点很重要。
Redis 更偏高性能、可接受一定最终一致性的场景。
如果你面对的是:
- 强一致协调
- 严格主从切换语义
- 更重的分布式一致性约束
那就不能只看“Redis 很快”,还要考虑 ZooKeeper 这类更偏协调器定位的组件。
八、几个容易踩的坑
1. 把缓存一致性要求想得过高
很多缓存场景允许短暂脏数据,这是正常的工程取舍。
2. 直接自己手写一版分布式锁就上线
最简单的 setnx 只是起点,不是完整方案。
3. Redis 里无限堆数据
没有过期策略、没有容量预估、没有热点治理,最终都会演变成内存问题。
4. 用 Redis 承担它本来不擅长的职责
它适合做高性能共享状态,不适合替代数据库承载完整业务语义。
一句话总结
Redis 最适合做的是“高性能的临时共享状态和缓存层”,而不是替代数据库去承接所有业务语义。
真正把它用好,关键不是多记命令,而是搞清楚每种用法的一致性边界、锁语义和失效策略。