当前位置: 首页 > news >正文

缓存穿透、缓存击穿、缓存雪崩

缓存穿透

说明:缓存穿透是指客户端请求缓存和数据库都不存在的数据,这样缓存永远不会生效,这些请求都会打到数据库上。

如图:每次请求都经过3、4、5,每次都要操作数据库,也就是缓存无效了。如果是1w 请求,1w 请求最终都打到数据库上。

解决方案

常见的解决方案有两种:缓存空对象,使用布隆过滤器;

  • 缓存空对象

客户端请求缓存和数据库都不存在的数据,返回时将控制设置到redis中,并且设置过期时间。

public Product getProductCache(String productId) {
    // 从缓存中获取数据
    String key = (String)redisTemplate.opsForValue().get("productId");

    if (key == null) {
        // 从数据库获取查询
        Product product = ProductService.selectByProductId(productId);
        if (Objects.nonNull(product)) {
            // 数据库存在数据,则重新设置缓存
            redisTemplate.opsForValue().set(productId, JSON.toJSONString(product), 3000L);
            return product;
        }else{
            // 从缓存和数据库都是空,那么把空值放进缓存,设置过期时间,防止缓存穿透
            redisTemplate.opsForValue().set(productId, null, 2000L);
            return null;
        }
    }
    return JSON.parseObject(key, Product.class);
}
  • 使用布隆过滤器

布隆过滤器本次不做说明。

缓存击穿

说明:缓存击穿是针对热点 key 而言,某个瞬间大量请求该 key,且 key 不存在,这些请求全部打到数据库上。

如图:热键瞬间失效,大量的请求都打到了 mysql 上,mysql 可能承受不住如此如此之高的请求量。

解决方案

常见的解决方案有两种:加互斥锁,热点数据不过期;

  • 加互斥锁

在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,直接走缓存。

  • 热点数据不过期

直接将缓存设置为不过期,然后由定时任务去异步加载数据,更新缓存,或者在 key 对应的 value 内容发生变化主动去更新缓存。

缓存雪崩

说明:大量的热点 key 设置了相同的过期时间,导在缓存在同一时刻全部失效,造成瞬时数据库请求量大、压力骤增,引起雪崩,甚至导致数据库被打挂。

如图:key1~key8 的过去时间相同,同时失效,对于 key1~key8 的所有查询请求都打到了 mysql 上。

解决方案

常见的解决方案有两种:打散 key 过期时间,热点数据不过期,加互斥锁;

  • 打散 key 过期时间

既然是大量缓存集中失效,那最容易想到就是让他们不集中生效。可以给缓存的过期时间时加上一个随机值时间,使得每个 key 的过期时间分布开来,不会集中在同一时刻失效。

  • 加互斥锁

在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,直接走缓存。

  • 热点数据不过期

直接将缓存设置为不过期,然后由定时任务去异步加载数据,更新缓存,或者在 key 对应的 value 内容发生变化主动去更新缓存。

相关文章:

  • HIVE自定义UDAF函数
  • java计算机毕业设计基于安卓Android的校园助手APP
  • 计算机网络笔记(王道考研) 第四章:网络层
  • MySQL必知必会---检索数据
  • ORACLE认证课程
  • emplace()
  • 【代码随想录】回溯算法刷题
  • Pyhon——datetime、calendar模块
  • 爆刷leetcode——链表(二)
  • 【翻译】Style-Aware Normalized Loss for Improving Arbitrary Style Transfer
  • Spring的component-scan XML配置和@ComponentScan注解配置
  • Java 基础知识回顾(一)
  • shell脚本之函数的引入
  • JDK的下载与安装详细教程
  • 刷题记录(NC231128 Steadily Growing Steam,NC21467 [NOIP2018]货币系统,NC235950 多重背包)
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • Idea+maven+scala构建包并在spark on yarn 运行
  • JDK9: 集成 Jshell 和 Maven 项目.
  • ReactNative开发常用的三方模块
  • Sass Day-01
  • Webpack入门之遇到的那些坑,系列示例Demo
  • yii2中session跨域名的问题
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 服务器之间,相同帐号,实现免密钥登录
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 前端临床手札——文件上传
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 实现菜单下拉伸展折叠效果demo
  • 使用docker-compose进行多节点部署
  • 源码安装memcached和php memcache扩展
  • 正则与JS中的正则
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • (1)STL算法之遍历容器
  • (27)4.8 习题课
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (转) 深度模型优化性能 调参
  • (转)Oracle 9i 数据库设计指引全集(1)
  • *** 2003
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • **PHP分步表单提交思路(分页表单提交)
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .net反编译的九款神器
  • .Net中的设计模式——Factory Method模式
  • :如何用SQL脚本保存存储过程返回的结果集
  • @property python知乎_Python3基础之:property
  • [2018-01-08] Python强化周的第一天
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [C#基础知识]专题十三:全面解析对象集合初始化器、匿名类型和隐式类型
  • [cocos creator]EditBox,editing-return事件,清空输入框
  • [ES-5.6.12] x-pack ssl