问题解释:
- 缓存穿透:查询不存在的数据,缓存和数据库都没有,导致所有请求都打到数据库上。
- 缓存击穿:一个Key过期,大量请求打到数据库。
- 缓存雪崩:大量Key同时过期,导致大量请求打到数据库。
解决方案:
缓存穿透:
- 使用布隆过滤器:在缓存之前加一个布隆过滤器,查询时先检查数据是否存在。
- 缓存空值:如果数据库查询不到,也缓存一个特殊值,如空字符串或者NULL,并设置较短的过期时间。
缓存击穿:
- 加互斥锁:当Key过期时,先加锁,只有一个线程去数据库查询,其他线程等待。
- 预先载入缓存:定时预先更新缓存,或者在高峰时间预热缓存。
缓存雪崩:
- 设置随机过期时间:使得Key不会在同一时间过期。
- 监控告警:提前预警,在大量Key即将过期时,预热缓存。
- Redis集群部署:分散Key的存储和访问压力。
示例代码(伪代码):
# 缓存穿透 - 布隆过滤器
def is_key_exist(key):
# 布隆过滤器判断Key是否存在
return bloom_filter.is_exist(key)
def get_data(key):
if not is_key_exist(key):
return None
data = redis.get(key)
if data is None:
data = db.get(key)
if data is not None:
redis.set(key, data, ex=3600)
return data
# 缓存击穿 - 互斥锁
def get_data_with_lock(key):
lock = acquire_lock(key)
if lock:
data = redis.get(key)
if data is None:
data = db.get(key)
if data is not None:
redis.set(key, data, ex=3600)
release_lock(key)
else:
sleep(1) # 等待1秒,再次尝试获取数据
get_data_with_lock(key)
return data
# 缓存雪崩 - 随机过期时间
def set_random_expire(key, data, expire_time):
random_expire = random.randint(expire_time//2, expire_time)
redis.set(key, data, ex=random_expire)
注意:以上代码仅为示例,实际应用需要根据业务场景和架构进行调整。