.net core redis 缓存穿透 缓存击穿 缓存雪崩

缓存 击穿 就是 缓存过期了 就需要查询数据库 高并发 数据库有可能挂了

缓存 击穿 解决方法 缓存预热 上线前 把数据倒到 redis里 过期时间 不用设置过期  就 永不过期 就行

缓存 穿透 就是 查询的时候 缓存没查到 数据库也没查到 ,类似的情况 比如 查询用户 get/user/id 我瞎写一个 可能就是 缓存中没有 数据库中也没有 这个id数据

就是走了一圈 即 消耗了redis的资源 又消耗了 数据库资源 浪费资源 而且高并发 还能把 数据库搞挂了 可恶

缓存 穿透的解决方法  直接点用 布隆过滤 期 先查询过滤期有没有该 数据key 如果有才查询缓存 如果没有就返回null 

缓存 雪崩 就是 同一时间 redis 的数据过期了 失效了 或者 redis崩了 造成查询不到了 只能查询数据库了 也会把 数据库搞挂了 太可恶了

缓存雪崩 就搞搞个 集群就解决了,过期时间搞个随机数别写成一样的 俗称打散总是搞的高大上的名称 但是 解释起来就那么回事 

下面来 一一解决这些问题

先 nuget 下在布隆过滤器 

BloomFilter.NetCore

由于 我用的 是CSRedisCore 所以下载这个 github  还适配其他的 redis 的链接库 

BloomFilter.CSRedis.NetCore

源码地址 使用方式 人家写的 挺详细的 

vla/BloomFilter.NetCore: Library Bloom filters in C# with optional Redis-backing (github.com)

不墨迹了 说了那么多 

直接上代码

            //添加 布隆过滤器
            services.AddBloomFilter(setupAction =>
            {
                setupAction.UseCSRedis(new FilterCSRedisOptions
                {
                    Name = "Redis1",
                    RedisKey = "CSRedis1",
                    Client = services.BuildServiceProvider().GetRequiredService<CSRedisClient>(),//这里就演示一下后期需要封装 用的是CSRedisCore 给客户端赋值
                    ConnectionStrings = new[] { "192.168.0.192" }.ToList()
                });
            });

测试一下

 private readonly IService<Order> _service;
        private readonly CSRedisClient _cSRedisClient;
        private readonly ICapPublisher _capPublisher;
        private readonly IBloomFilter _bloomFilter;
        public OrdersController(IService<Order> service,
            CSRedisClient cSRedisClient,
           ICapPublisher capPublisher,
           IBloomFilter bloomFilter
            )
        {
            _service = service;
            _cSRedisClient = cSRedisClient;
            _capPublisher = capPublisher;
            _bloomFilter = bloomFilter;
        }


 

   [HttpPost]
        public async Task<IActionResult> CreateAsync([FromBody] Order order)
        {

            string id = order.Id.ToString();
            string key = $"{RedisKeyPrefix.OrderPrefix}:{id}";
            //存到redis 现在 1个0.5秒
            _cSRedisClient.HSet(key, id, order);
            //为了避免缓存不被击穿 不设置过期时间
            //await _cSRedisClient.ExpireAsync(key, TimeSpan.FromSeconds(12));

            //为了避免缓存不被穿透 添加布隆过滤器
            await _bloomFilter.AddAsync(key);

            await _capPublisher.PublishAsync(CapKeyPrefix.CapOrderCreate, order);
            //直接添加 数据库 1个请求 需要20秒
            //var orderEntity = await _service.CreateAsync(order);
            //await _service.SaveChangeAsync();
            //return Ok(orderEntity);
            return Ok(order);
        }


        [HttpGet("{Id}")]
        public async Task<IActionResult> GetAsync([FromRoute] int Id)
        {
            string id = Id.ToString();
            string key = $"{RedisKeyPrefix.OrderPrefix}:{id}";
            Order order = null;
            //布隆过滤器 如果存在就查询 如果不存在就返回null  布隆过滤器 的 数据应该是预热的时候添加进去
            bool isExits = await _bloomFilter.ContainsAsync(key);
            if (isExits)
            {
                //单条查询 20请求并发 最大值 45-138毫秒
                //Order order = await _service.GetAsync(Id);
                //redis 单条查询 20请求并发 最大值 42毫秒
                order = await _cSRedisClient.HGetAsync<Order>(key, id);
                if (order == null)
                {
                    //如果 缓存中没有数据,数据过期 将查询数据库 这就造成了 缓存击穿了 
                    //解决方式  先数据预热缓存的数据不设置过期时间 保证查询的数据 一定存在
                    //解决了缓存击穿了 如果我随意写个Id  这个时候 就会出现 缓存中没有 数据库中也没有 如果
                    //高并发 或者恶意攻击 那么 就会 一直查询数据库 会拖垮数据库
                    //此时用 布隆过滤器解决
                    order = await _service.GetAsync(Id);
                }
            }
            //var orderEntity = await _service.UpdateAsync(order);
            //await _service.SaveChangeAsync();
            //return Ok(orderEntity);
            return Ok(order);
        }

以上就是测试 

这个就是刚创建的布隆过滤器 

 

posted on 2023-06-01 21:47  是水饺不是水饺  阅读(160)  评论(0)    收藏  举报

导航