一.缓存穿透

缓存穿透概念

缓存穿透是指查询一个一定不存在的数据,在数据库没有,自然在缓存中也不会有。导致用户查询的时候,在缓存中找不到对应key的value,每次都要去数据库再查询一遍,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

缓存穿透解决方案

有很多种方法可以有效地解决缓存穿透问题。

缓存空值

如果一个查询返回的数据为空(不管是数据不存在,还是系统故障)我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过5分钟。通过这个设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库。

采用布隆过滤器BloomFilter

在缓存之前加一层BloomFilter,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。在查询的时候先去BloomFilter去查询key是否存在,如果不存在就直接返回,存在再去查询缓存,缓存中没有再去查询数据库。对BloomFilter有兴趣的可以看我的另一篇文章教你用BitMap排序、查找和存储大量数据。

二.缓存雪崩

缓存雪崩概念

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。

缓存雪崩解决方案

设置不同的过期时间,让缓存失效的时间点尽量均匀

在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

考虑用队列或者锁让程序执行在压力范围之内,当然这种方案可能会影响并发量;

热点数据可以考虑不失效。

三.缓存击穿

缓存击穿概念

在平常高并发的系统中,大量的请求同时查询一个key,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去,造成数据库请求量过大,压力剧增,这种现象我们称为缓存击穿。

缓存击穿解决方案

使用互斥锁(mutex key)

业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存,否则,就重试整个get缓存的方法。

SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

redis2.6.1之前版本未实现setnx的过期时间,这里给出两种版本代码参考:

//2.6.1之前
String get(String key) {  String value = redis.get(key);  if (value  == null) {  if (redis.setnx(key_mutex, "1")) {  // 3 min timeout to avoid mutex holder crash  redis.expire(key_mutex, 3 * 60)  value = db.get(key);  redis.set(key, value);  redis.delete(key_mutex);  } else {  //其他线程休息50毫秒后重试  Thread.sleep(50);  get(key);  }  }
}
//2.6.1之后
String get(key) {String value = redis.get(key);if (value == null) { //代表缓存值过期//设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load dbif (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表设置成功value = db.get(key);redis.set(key, value, expire_secs);redis.del(key_mutex);} else {  //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可sleep(50);get(key);  //重试}} else {return value;      }}

永远不过期

这里的“永远不过期”包含两层意思:

  1. 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期;
  2. 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期。
String get(final String key) {  V v = redis.get(key);  String value = v.getValue();  long timeout = v.getTimeout();  if (v.timeout <= System.currentTimeMillis()) {  // 异步更新后台异常执行  threadPool.execute(new Runnable() {  public void run() {  String keyMutex = "mutex:" + key;  if (redis.setnx(keyMutex, "1")) {  // 3 min timeout to avoid mutex holder crash  redis.expire(keyMutex, 3 * 60);  String dbValue = db.get(key);  redis.set(key, dbValue);  redis.delete(keyMutex);  }  }  });  }  return value;
}

从实战看,这种方法对于性能非常友好,唯一不足的就是构建缓存时候,其余线程(非构建缓存的线程)可能访问的是老数据,但是对于一般的互联网功能来说这个还是可以忍受。

猜你感兴趣
Redis专题-集群模式
Redis专题-持久化方式
Redis专题-底层数据结构与使用场景
Redis专题-缓存穿透、缓存雪崩、缓存击穿

更多文章请点击:更多…

Redis专题-缓存穿透、缓存雪崩、缓存击穿相关推荐

  1. Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)

    一.概述 ① 缓存穿透:大量请求根本不存在的key(下文详解) ② 缓存雪崩:redis中大量key集体过期(下文详解) ③ 缓存击穿:redis中一个热点key过期(大量用户访问该热点key,但是热 ...

  2. 什么是缓存穿透、雪崩、击穿以及解决方案

    目录 1.缓存穿透 2.缓存雪崩 3.缓存击穿 4.区别总结 5.加锁实现 1.缓存穿透 描述: 在查询一个数据时,在缓存中不存在,将去数据库进行查询并且数据库中也不存在数据,使得缓存中一直不会存在数 ...

  3. 一篇吃透Redis缓存穿透、雪崩、击穿问题

    前言:在学Redis之前我们查询数据的时候都是直接查询数据库的,但是这样会有一个潜在的问题:"如果用户量很大,所有请求都去访问数据库,那么会使数据库压力过大,导致性能下降甚至宕机" ...

  4. mysql数据库击穿_面试中经常出现的缓存穿透、雪崩和击穿到底是什么?

    对于缓存穿透.缓存雪崩和缓存击穿常常出现在面试中,今天来看看它到底是何方神圣 ​ ​ redis缓存穿透 ​理解重在穿透吧,也就是访问透过redis直接经过mysql,通常是一个不存在的key,在数据 ...

  5. 缓存穿透、雪崩、击穿的区分

    缓存穿透: 是指用户查询一个不存在的数据,由于缓存无法命中,将去查询数据库,但是数据库也无此记录,并且出于容错考虑,我们没有将这次查询的null写入缓存,这将导致这个不存在的数据每次请求都要到存储层去 ...

  6. Redis全部知识总结(概念、安装、用法、数据类型、事务、持久化、Jeids、订阅系统、缓存穿透及雪崩等)

    Redis NoSql简述 Nosql概念 Nosql的四大分类 Redis概述 Redis的安装 安装文件 Window下安装 Linux下安装 redis-benchmark 压力测试工具 五大数 ...

  7. Redis11_缓存穿透和雪崩

    Redis11_缓存穿透和雪崩 缓存穿透 用户查询某个数据时,会先在redis缓存中查询,如果缓存没有命中,会去持久层数据库MySQL中查询,如果此时依然没有命中,将返回null,不会写入缓存. 当同 ...

  8. 二十七、Redis缓存穿透和雪崩(完)

    Redis缓存穿透和雪崩 一.服务的高可用问题 在这里我们不会详细的区分析解决方案的底层! Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面.但同时,它也带来了一些问题.其中 ...

  9. 21_Redis_浅析Redis缓存穿透和雪崩

    为什么了解缓存穿透和雪崩:保证服务的高可用问题 Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面.但同时,它也带来了一些问题.其中,最要害的问题,就是数据的一致性问题,从严格 ...

  10. Redis 缓存穿透、雪崩、缓存数据库不一致、持久化方式、分布式锁、过期策略

    1. Redis 缓存穿透 1.1 Redis 缓存穿透概念 访问了不存在的 key,缓存未命中,请求会穿透到 DB,量大时可能会对 DB 造成压力导致服务异常. 由于不恰当的业务功能实现,或者外部恶 ...

最新文章

  1. windows php-cgi命令选项,windows平台上php-cgi调用系统命令(net)时执行异常,但在命令行下能正常执行,问题会出在哪呢?...
  2. CTFshow php特性 web134
  3. 15个学习习惯,受益一生(强烈推荐)
  4. 涂鸦板练习(20200214)
  5. 限制tomcat带宽_必看的Tomcat性能优化
  6. [html] html5哪些标签可以优化SEO?
  7. 10年腾讯技术专家有话对你说
  8. java velocity 语法_Velocity 语法
  9. php表决器代码,adder3 此源代码是基于Verilog语言的七人投票表决器 、2 个 联合开发网 - pudn.com...
  10. macbook只有windows下安装os系统、trackpad++下载
  11. Redis数据存储类型
  12. Windows10查看本机连接过的WiFi密码
  13. 【微信小程序】深入学习小程序基本目录文件与代码结构
  14. C#串口开发案例:迈瑞血球分析仪
  15. 基于ZYNQ的开源CANopen协议栈CANFestival移植
  16. 成年人英语速成指南(附资源及工具)
  17. 1.background、color、渐变
  18. 修改Centos7.6服务器时间
  19. Vue开发入门(二) | 说说Vue全家桶有哪些~
  20. [转]谈NAND Flash的底层结构和解析

热门文章

  1. 【Win32汇编】数组累加
  2. 函数指针和shellcode
  3. Python正则表达式之额外补充(7)
  4. 2020-12-7(字节,半字,字,双字总结)
  5. C++简单使用priority_queue
  6. 005 定位控件输入call
  7. 邻接矩阵和邻接表的相互转化
  8. 三对角矩阵(带状矩阵)的压缩存储原理
  9. HTML之iframe内联框架
  10. MySQL之alter和upate