Python 后端基础(八):Redis 高频问题,缓存穿透、击穿、雪崩和分布式锁
Redis 不只问数据类型,更常问缓存穿透、缓存击穿、缓存雪崩、分布式锁和限流。本文用项目场景讲清这些问题是什么、为什么发生、怎么解决。
【一、为什么 Redis 高频问题很重要】
缓存用得好可以提升性能,用不好会把系统拖垮。
很多生产事故不是因为不会写 `GET` 和 `SET`,而是因为:
- 大量不存在的数据请求打到数据库。
- 热点 key 失效瞬间数据库被打爆。
- 大批缓存同时过期。
- 分布式锁没有释放导致业务阻塞。
- 限流没做导致接口被刷爆。
所以 Redis 高频问题非常适合写进项目和面试回答。
【二、缓存穿透】
缓存穿透指:请求的数据既不在 Redis,也不在 MySQL。
例如有人不断请求不存在的商品 id:
GET /products/999999999
每次流程都是:
查 Redis -> 没有
查 MySQL -> 也没有
返回不存在
大量这种请求会绕过缓存,直接打到数据库。
解决方案:
1. 缓存空值:数据库查不到,也把空结果缓存一小段时间。
2. 布隆过滤器:先判断 id 是否可能存在,不可能存在就直接拦截。
3. 参数校验:明显非法的 id 直接拒绝。
缓存空值示例:
python:
if user is None:
redis.set(cache_key, "null", ex=60)
return None
【三、缓存击穿】
缓存击穿指:某个热点 key 过期,大量请求同时打到数据库。
比如首页热门商品缓存过期的一瞬间,几千个请求同时过来。
解决方案:
1. 热点 key 设置较长过期时间,甚至逻辑过期。
2. 加互斥锁,只允许一个请求回源数据库。
3. 后台定时刷新热点缓存。
互斥锁思想:
发现缓存没有
-> 尝试获取锁
-> 获取锁的请求查数据库并重建缓存
-> 其他请求等待或返回旧值
【四、缓存雪崩】
缓存雪崩指:大量 key 在同一时间过期,导致请求同时打到数据库。
常见原因:
- 批量设置缓存时用了相同过期时间。
- Redis 故障。
- 热点缓存集中失效。
解决方案:
1. 过期时间加随机值。
2. 热点数据预热。
3. 多级缓存。
4. 限流和降级。
5. Redis 高可用部署。
示例:
python:
import random
expire_seconds = 3600 + random.randint(0, 300)
redis.set(cache_key, value, ex=expire_seconds)
【五、分布式锁是什么】
分布式锁用于多个服务实例之间控制同一资源的并发访问。
比如秒杀扣库存:
服务实例 A、B、C 同时处理同一个商品库存
如果不加控制,可能出现超卖
Redis 可以用 `SET key value NX EX seconds` 实现基础分布式锁。
SET lock:product:100 request_id NX EX 10
含义:
- `NX`:key 不存在时才设置成功。
- `EX 10`:10 秒后自动过期,防止死锁。
- `request_id`:锁的持有者标识,释放锁时要校验。
【六、释放锁为什么要校验 value】
不能简单地:
DEL lock:product:100
因为可能出现:
A 获取锁,业务执行太慢,锁过期
B 获取到新锁
A 执行完直接 DEL,把 B 的锁删了
所以释放锁要判断 value 是否是自己的。
真实项目建议使用成熟客户端或 Redisson 这类方案。Python 里可以结合 Lua 脚本保证判断和删除的原子性。
【七、Redis 限流怎么做】
限流用于防止接口被刷爆。
简单计数器限流:
每个用户每分钟最多请求 60 次
key = rate:user:1001:202606081930
流程:
请求进来 -> INCR key
第一次设置过期时间 60 秒
如果计数超过阈值 -> 拒绝
适合登录接口、短信验证码、AI 调用接口。
【八、常见坑】
- 缓存穿透只靠“查不到返回空”,但不缓存空值。
- 所有缓存过期时间完全一样。
- 分布式锁没有过期时间,业务异常后永远不释放。
- 释放锁不校验 value,误删别人的锁。
- 把 Redis 分布式锁当成绝对可靠,不考虑超时和重试。
- AI 接口不做限流,导致成本失控。
更多推荐
所有评论(0)