【Redis笔记】缓存穿透、缓存雪崩、缓存击穿解决方案-.Neterr-博客园: 【Redis笔记】缓存穿透、缓存雪崩、缓存击穿解决方案缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。
解决方案
缓存空对象
布隆过滤
增强id的复杂度,避免被猜测id规律
做好数据的基础格式校验
加强用户权限校验
做好热点参数的限流缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
解决方案
给不同的Key的TTL添加随机值
利用Redis集群提高服务的可用性
给缓存业务添加降级限流策略
给业务添加多级缓存缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
解决方案
- 互斥锁
性能受影响,线程需要等待,实现简单,保证一致性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; } }var _avatarCache = new WaitToFinishMemoryCache<byte[]>(); var myAvatar = await _avatarCache.GetOrCreate(userId, async () => await _database.GetAvatar(userId));
- 逻辑过期
性能好,线程无需等待,实现复杂
缓存数据时添加一个逻辑过期时间,并不是真正的过期时间
实现逻辑:
定义一个缓存对象用于附加逻辑过期时间,如:public class CacheData<T>{ public T Data{get;set;} public DateTime ExpireTime{get;set;} }