通常我们使用缓存中间件的方式 将数据库的热点数据缓存到Redis中 尽量去缓存中查找数据,目的就是为了减轻数据库的压力
文章图片
那什么是 缓存穿透,缓存击穿 与 缓存雪崩 呢 ?
缓存穿透 当Redis中不存在某个key时,将对数据库进行查询操作 但如果数据库也不存在 就会造成每一个请求即查询redis也会查询数据库 这就是缓存穿透
文章图片
比如说一个查询接口 查询范围在 1~1000 但是遇到不怀好意的用户 大量请求 1000 ~ … 查询不存在的信息
将给数据库造成巨大的压力 并且Redis缓存形同虚设了
解决办法
一般处理办法有两种
方式一 : 利用布隆过滤器 首先将Redis中的key全部添加到布隆过滤器中 布隆过滤器判断不存在的一定Redis中也没有 可以过滤掉绝大部分恶意请求 但是 布隆过滤器不是百分百正确的 判断有的 可能redis中也不存在
方式二: 缓存空值
当从数据库中没有查询到数据的时候,也给redis中缓存一个空值 并且返回这个空值 这样下次同样信息的请求过来时,redis就能直接处理不用再去查询数据库了
缓存击穿 【Redis|缓存穿透 缓存击穿 缓存雪崩 这三者是什么 如何处理】当某一个时刻 redis中某一个 热点 Key 过期,大量的并发请求打到数据库上 可能造成数据库崩溃 打在一个点上 这就是缓存击穿
缓存击穿 与 缓存穿透的区别在于 缓存击穿是Redis中过期,数据库中有 而 缓存穿透是Redis中没有,数据库中也没有
文章图片
缓存击穿最大的问题在于大量请求发现Redis中的数据找不到了,要去数据库中查找,而数据库中是有数据的 所以我们只需要控制请求数
放一个请求去查询数据库,查到数据后,将数据写回 Redis 此时再放其他请求去查询Redis , 此时Redis已经有了相应的数据
解决办法
加分布式锁 可以使用 Redis 或者 Mysql 都行 Redis做分布式锁相对简单
判读key是否存在,不存在则创建key,value,同时设置过期时间,防止死锁 要保证原子性 调用 setIfAbsent 方法
//原子操作 设置 UUID 与 过期时间 30 秒
Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(RedisConst.SKUKEY_LOCK + skuId, uuid, 30, TimeUnit.SECONDS);
key 设置前缀和标识 value设置成锁持有者的唯一标识 防止锁过期后误删其他线程的锁
缓存雪崩 缓存雪崩 同一时间Redis中大量热点key过期 造成数据库处理大量请求最后崩溃
相比缓存击穿 过期的热点key数量更多
解决办法
设置热点key过期时间时,添加一个随机值 避免同一时间过期
推荐阅读
- linux|Linux 安装项目软件 MySql Redis Nginx RabbitMQ Docker 轻松 详细
- CS 325 Rod Cutting:
- 历史上的今天|【历史上的今天】1 月 28 日(Sun 联合创始人诞生;图灵奖数据库先驱逝世;雅虎收购 GeoCities)
- Java|Java面试突击系列(十二)(数据库分库分表的面试连环炮)
- MyBatis-Plus|Springboot(使用IDEA自动生成java实体类Mysql逆向工程效率神器使用讲解)
- redis|Reids解决海量重复提交问题
- 数据库|redis的常见问题总结
- 关于Spring|MySQL 主从复制数据不一致,怎么办()
- 数据库|springboot 配置Druid多数据源监控