
1) 【一句话结论】:采用多级缓存(本地+Redis)结合TTL随机化、热点key加锁、主动预热策略,通过随机过期时间分散失效时间、对热点key加互斥锁避免并发更新,并提前加载热点数据,有效避免缓存雪崩。
2) 【原理/概念讲解】:缓存雪崩是指大量缓存key同时过期失效,导致流量集中到后端数据库。解决方案:
3) 【对比与适用场景】:
| 策略 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| TTL随机化 | 为缓存key添加随机过期时间偏移 | 分散失效时间,降低集中压力 | 所有缓存key(尤其非热点) | 需动态调整偏移量,避免过期时间过长 |
| 热点key加锁 | 对高频访问key加分布式锁,控制并发更新 | 保证单线程更新缓存 | 热门课程列表、用户信息等高频key | 锁粒度不宜过大,避免影响性能;锁超时处理 |
| 多级缓存 | 本地缓存+Redis,本地优先回源 | 减少Redis压力,快速响应 | 高频访问数据(如课程列表) | 本地缓存与Redis数据一致性维护(如缓存失效后回源) |
| 主动预热 | 预先加载核心数据到缓存 | 减少首次访问数据库压力 | 系统启动、低峰期加载热点数据 | 预热数据量需合理,避免占用过多资源 |
4) 【示例】(伪代码):
假设课程列表的缓存key为course_list,过期时间设为随机值(1-2小时),实现如下:
def get_course_list():
# 1. 检查本地缓存
local_cache = get_local_cache("course_list")
if local_cache:
return local_cache
# 2. 检查Redis缓存
redis_key = "course_list"
redis_cache = redis.get(redis_key)
if redis_cache:
set_local_cache("course_list", redis_cache)
return redis_cache
# 3. 缓存未命中,加锁处理
lock_key = f"course_list_lock"
with redis_lock(lock_key, timeout=10): # 分布式锁
local_cache = get_local_cache("course_list")
if local_cache:
return local_cache
redis_cache = redis.get(redis_key)
if redis_cache:
set_local_cache("course_list", redis_cache)
return redis_cache
# 数据库查询
courses = db.query("select * from courses where is_hot=1")
# 更新缓存
redis.setex(redis_key, random_ttl(3600, 7200), json.dumps(courses))
set_local_cache("course_list", json.dumps(courses))
return courses
其中random_ttl函数生成1-2小时的随机过期时间,redis_lock是Redis分布式锁实现(如Redlock)。
5) 【面试口播版答案】:
“面试官您好,针对教育平台课程列表、用户信息等常用数据的缓存策略,我会从多级缓存、TTL随机化、热点key加锁、主动预热这几个方面设计,并避免缓存雪崩。首先,采用本地缓存(如Java的ConcurrentHashMap)+Redis的多级缓存架构,本地缓存优先,减少Redis压力。其次,对缓存key设置随机过期时间(比如课程列表的过期时间在1-2小时之间随机),避免大量key同时失效。对于高频访问的热点key(如热门课程列表),使用Redis分布式锁(如SETNX)保证同一时间只有一个请求去数据库查询并更新缓存,其他请求等待,防止并发更新导致缓存失效。另外,系统启动或低峰期会主动加载核心数据到缓存(如热门课程列表),减少首次访问的数据库压力。通过这些措施,可以有效分散缓存失效时间,避免流量激增导致的雪崩问题。”
6) 【追问清单】:
7) 【常见坑/雷区】: