[Redis]——缓存击穿和缓存穿透及解决方案(图解+代码+解释)
缓存击穿:
解释:
缓存击穿是指缓存中没有但数据库中有的数据(如缓存服务器宕机或缓存过期),这时由于并发用户特别多,同时访问这个数据,导致所有的请求都到达数据库,造成数据库压力过大,甚至宕机。
解决方案:
- 设置热点数据永不过期。
- 使用互斥锁,保证同时只有一个请求去数据库查询数据,其他请求等待。
- 提前预热数据,保证热点数据在缓存中。
缓存穿透:
解释:
缓存穿透是指查询不存在的数据,缓存中和数据库中都没有,这样会导致用户请求直接打到数据库,造成数据库压力过大。
解决方案:
- 使用布隆过滤器,它可以检查一个元素是否在一个集合中。如果不在,直接返回,不查询数据库。
- 对于查询不到的数据,也可以在缓存中存储一个空值或默认值,并设置一个较短的过期时间。
- 使用互斥锁,同上述缓存击穿。
代码示例(伪代码):
# 缓存击穿:使用互斥锁
def get_data(data_id):
# 尝试从缓存获取数据
data = cache.get(data_id)
if data is not None:
return data
# 加锁,避免并发请求到数据库
with cache.lock(data_id):
# 再次检查缓存,防止缓存服务器宕机等情况
data = cache.get(data_id)
if data is None:
# 缓存中没有数据,从数据库加载
data = db.get(data_id)
if data is not None:
# 设置热点数据永不过期
cache.set(data_id, data, ttl=None if is_hot_data else 3600)
return data if data is not None else None
# 缓存穿透:使用布隆过滤器
from some_bloom_filter_library import BloomFilter
bf = BloomFilter(size=1000000, error_rate=0.001)
def get_data(data_id):
# 使用布隆过滤器检查数据是否存在
if not bf.might_contain(data_id):
return None
# 尝试从缓存获取数据
data = cache.get(data_id)
if data is not None:
return data
# 数据库中也没有,返回默认值或空值,并设置短暂过期时间
data = db.get(data_id)
if data is None:
cache.set(data_id, None, ttl=5)
else:
cache.set(data_id, data, ttl=3600)
return data if data is not None else None
# 初始化时,将所有数据ID添加到布隆过滤器中
for data_id in db.get_all_data_ids():
bf.add(data_id)
以上代码示例展示了缓存击穿和穿透的基本解决方案,具体实现可能需要根据实际应用场景和技术栈进行调整。
评论已关闭