【Redis笔记】缓存穿透、缓存雪崩、缓存击穿解决方案
缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。
解决方案
缓存空对象
布隆过滤
增强id的复杂度,避免被猜测id规律
做好数据的基础格式校验
加强用户权限校验
做好热点参数的限流
缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
解决方案
给不同的Key的TTL添加随机值
利用Redis集群提高服务的可用性
给缓存业务添加降级限流策略
给业务添加多级缓存
缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
解决方案
- (1) 互斥锁(分布式锁)
原理:当缓存失效时,通过Redis的SETNX命令(或SET key value NX EX)加锁,仅允许一个线程查询数据库并重建缓存,其他线程等待或重试。
public class WaitToFinishMemoryCache<TItem>
{
private MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
private ConcurrentDictionary<object, SemaphoreSlim> _locks = new ConcurrentDictionary<object, SemaphoreSlim>();
public async Task<TItem> GetOrCreate(object key, Func<Task<TItem>> createItem)
{
TItem cacheEntry;
if (!_cache.TryGetValue(key, out cacheEntry))// Look for cache key.
{
SemaphoreSlim mylock = _locks.GetOrAdd(key, k => new SemaphoreSlim(1, 1));
await mylock.WaitAsync();
try
{
if (!_cache.TryGetValue(key, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = await createItem();
_cache.Set(key, cacheEntry);
}
}
finally
{
mylock.Release();
}
}
return cacheEntry;
}
}
优点:强一致性,避免重复查询数据库。
缺点:线程阻塞可能影响性能,需设置锁超时防止死锁
。
* (2) 逻辑过期(异步刷新)
原理:在缓存Value中嵌入逻辑过期时间(如{data: "...", expireTime: 1672500000}),过期后异步更新缓存,期间返回旧数据。
实现步骤:
查询缓存,若逻辑未过期直接返回数据。
若过期,启动独立线程重建缓存,其他请求仍返回旧数据。
优点:高并发下性能更优,无阻塞。
缺点:短暂数据不一致,实现复杂度较高。

浙公网安备 33010602011771号