推荐答案
1. 设置缓存过期时间的随机值
为了避免大量缓存同时失效,可以为每个缓存项设置一个随机的过期时间。例如,在基础过期时间上增加一个随机的时间偏移量。
import random
import time
def set_cache_with_random_expiry(key, value, base_expiry, max_random_offset):
expiry = base_expiry + random.randint(0, max_random_offset)
redis_client.set(key, value, ex=expiry)2. 使用多级缓存
引入多级缓存机制,如本地缓存(如Guava Cache)与Redis缓存结合使用。当Redis缓存失效时,可以先从本地缓存中获取数据,减少对数据库的直接压力。
3. 缓存预热
在系统启动或低峰期,提前加载热点数据到缓存中,避免在高峰期缓存失效时大量请求直接打到数据库。
4. 限流与降级
在缓存失效时,通过限流和降级策略来控制请求的流量,避免数据库被大量请求压垮。可以使用Hystrix等工具来实现限流和降级。
5. 使用分布式锁
在缓存失效时,使用分布式锁(如Redis的SETNX命令)来确保只有一个请求去数据库加载数据,其他请求等待缓存更新。
// www.javascriptcn.com code example
def get_data_with_lock(key):
value = redis_client.get(key)
if value is None:
lock_key = f"lock:{key}"
if redis_client.setnx(lock_key, 1):
redis_client.expire(lock_key, 10) # 设置锁的过期时间
# 从数据库加载数据
value = load_data_from_db(key)
redis_client.set(key, value, ex=3600) # 设置缓存
redis_client.delete(lock_key)
else:
# 等待锁释放
time.sleep(0.1)
return get_data_with_lock(key)
return value本题详细解读
1. 缓存雪崩的定义
缓存雪崩是指在某一时刻,大量缓存同时失效,导致所有请求都直接打到数据库,造成数据库压力骤增,甚至导致数据库崩溃。
2. 缓存雪崩的原因
- 缓存集中过期:大量缓存在同一时间过期,导致请求直接访问数据库。
- Redis宕机:如果Redis服务宕机,所有缓存失效,请求也会直接打到数据库。
3. 解决方案的核心思想
- 分散缓存过期时间:通过设置随机的过期时间,避免大量缓存同时失效。
- 多级缓存:通过引入多级缓存,减少对单一缓存层的依赖。
- 限流与降级:在缓存失效时,通过限流和降级策略保护数据库。
- 分布式锁:确保只有一个请求去数据库加载数据,避免重复加载。
4. 实际应用中的注意事项
- 随机过期时间的范围:随机偏移量不宜过大,否则可能导致缓存过早失效。
- 多级缓存的同步:确保多级缓存之间的数据一致性。
- 限流与降级的阈值:根据系统的实际负载情况,合理设置限流和降级的阈值。
- 分布式锁的性能:分布式锁的使用可能会引入一定的性能开销,需谨慎使用。