【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}),过期后异步更新缓存,期间返回旧数据。
​实现步骤​:
查询缓存,若逻辑未过期直接返回数据。
若过期,启动独立线程重建缓存,其他请求仍返回旧数据。
​优点​:高并发下性能更优,无阻塞。
​缺点​:短暂数据不一致,实现复杂度较高。

posted @ 2020-07-05 11:38  .Neterr  阅读(523)  评论(0)    收藏  举报