出处:https://www.cnblogs.com/chanshuyi/p/how_to_deal_with_massive_request_in_redis.html

从第一个缓存框架 Memcached 诞生以来,缓存就广泛地存在于互联网应用中。如果你的应用流量很小,那么使用缓存可能并不需要做多余的考虑。但如果你的应用流量达到了成百上千万,那么你就不得不考虑深层次的缓存问题:缓存穿透、缓存击穿与缓存雪崩

缓存穿透

缓存穿透是指查询一个一定不存在的数据,因为这个数据不存在,所以永远不会被缓存,所以每次请求都会去请求数据库。

例如我们请求一个 UserID 为 -1 的用户数据,因为该用户不存在,所以该请求每次都会去读取数据库。在这种情况下,如果某些心怀不轨的人利用这个存在的漏洞去伪造大量的请求,那么很可能导致DB承受不了那么大的流量就挂掉了。

对于缓存穿透,有几种解决方案,一种是事前预防,一种是事后预防。

事前预防。其实就是对所有请求都进行参数校验,把绝大多数非法的请求抵挡在最外层。在我们举的这个例子中,那么就是做参数校验,对于 UserID 小于 0 的请求全部拒绝。但即使我们做了全面的参数校验,还是可能存在漏网之鱼,会出现一些我们没想到的情况。

例如我们的 UserID 是递增的,那么如果有人请求一个 UserID 很大的用户信息(例如:1000000),而我们的 UserID 最大也就 10000。这个时候,你不可能限制 UserID 大于 1 万的就是非法的,或者说大于 10 万就是非法的,所以该用户ID肯定可以通过参数校验。但该用户确实不存在,所以每次请求都会去请求数据库。

其实上面只是我所能想到的一种情况,我们没想到的情况肯定还有很多。对于这些情况,我们能做的就是时候预防。

事后预防。事后预防说的就是当查询到一个空的结果时,我们仍然将这个空的结果进行缓存,但是设置一个很短的过期时间(例如一分钟)。在这里我们可以看到,其实我们并没有完全预防非法请求,只不过是将非法请求的风险让承受能力更强的redis去承担,让承受能力稍弱的数据库更安全。

通过上面这两种处理方式,我们基本可以解决缓存穿透的问题。事前预防解决80%的非法请求,剩下的20%非法请求则使用Redis转移风险。

缓存击穿

如果你的应用中有一些访问量很高的热点数据,我们一般会将其放在缓存中以提高访问速度。另外,为了保持时效性,我们通常还会设置一个过期时间。但是对于这些访问量很高的KEY,我们需要考虑一个问题:当热点KEY在失效的瞬间,海量的请求会不会产生大量的数据库请求,从而导致数据库崩溃?

例如我们有一个业务 KEY,该 KEY 的并发请求量为 10000。当该 KEY 失效的时候,就会有 1 万个线程会去请求数据库更新缓存。这个时候如果没有采取适当的措施,那么数据库很可能崩溃。

其实上面这个问题就是缓存击穿的问题,它发生在缓存KEY的过期瞬间。对于这种情况,现在常用的解决方式有这么两种:互斥锁、永远不过期。

互斥锁

互斥锁指的是在缓存KEY过期去更新的时候,先让程序去获取锁,只有获取到锁的线程才有资格去更新缓存KEY。其他没有获取到锁的线程则休眠片刻之后再次去获取最新的缓存数据。通过这种方式,同一时刻永远只有一个线程会去读取数据库,这样也就避免了海量数据库请求对于数据库的冲击。

而对于上面说到的锁,我们可以使用缓存提供的一些原则操作来完成。例如对于 redis 缓存来说,我们可以使用其 SETNX 命令来完成。

public String get(key) {  String value = redis.get(key); if (value == null) { //缓存过期 if (redis.setnx(key_mutex, 1, 1 * 60) == 1) { value = db.get(key); redis.set(key, value, expireTime); redis.del(key_mutex); } else { //休眠片刻后重试 sleep(50); get(key); } } else { return value; } } 

上面的 key_mutex 其实就是一个普通的 KEY-VALUE 值,我们使用 setnx 命令去设置其值为 1。如果这时候已经有人在更新缓存KEY了,那么 setnx 命令会返回 0,表示设置失败。

永远不过期

从缓存的角度来看,如果你设置了永远不过期,那么就不会有海量请求数据库的情形出现。此时我们一般通过新起一个线程的方式去定时将数据库中的数据更新到缓存中,更加成熟的方式是通过定时任务去同步缓存和数据库的数据。

但这种方案会出现数据的延迟问题,也就是线程读取到的数据并不是最新的数据。但对于一般的互联网功能来说,些许的延迟还是能接受的。

缓存雪崩

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到数据库,最终导致数据库瞬时压力过大而崩溃。

例如我们有 1000 个KEY,而每个 KEY 的并发请求不大,只有 10 次。而缓存雪崩指的就是这 1000 个 KEY 在同一时间,同时失效,这个时候就突然有 1000 ** 10 = 一万次查询。

缓存雪崩导致的问题一般很难排查,如果没有事先预防,很可能要花很大力气才能找得到原因。对于缓存雪崩的情况,最简单的方案就是在原有失效时间的基础上增加一个随机时间(例如1-5分钟),这样每个缓存过期时间的重复率就会降低,从而减少缓存雪崩的发生。

总结

对于缓存穿透、缓存击穿、缓存雪崩这三个情景,许多人会搞不明白,甚至会混淆。

「缓存穿透」指的是请求不存在的数据,从而使得缓存形同虚设,缓存层被穿透了。例如我们请求一个 UserID 为 -1 的用户数据,因为该用户不存在,所以该请求每次都会去读取数据库。在这种情况下,如果某些心怀不轨的人利用这个存在的漏洞去伪造大量的请求,那么很可能导致DB承受不了那么大的流量就挂掉了。

「缓存击穿」指的是并发量很高的 KEY,在该 KEY 失效的瞬间有很多请求同同时去请求数据库,更新缓存。例如我们有一个业务 KEY,该 KEY 的并发请求量为 10000。当该 KEY 失效的时候,就会有 1 万个线程会去请求数据库更新缓存。这个时候如果没有采取适当的措施,那么数据库很可能崩溃。

「缓存雪崩」则是指缓存在同一时间同时过期,就像所有雪块同一时刻掉下来,像雪崩一样。例如我们有 1000 个KEY,而每个 KEY 的并发请求不大,只有 10 次。而缓存雪崩指的就是这 1000 个 KEY 在同一时间,同时失效,这个时候就突然有 1000 ** 10 = 一万次查询。

对于它们出现的情形,我们可以做一些总结:

「缓存穿透」是业务层面的漏洞导致非法请求,与请求量、缓存失效没关系。「缓存击穿」则只会出现在热点数据上,发生在缓存失效的瞬间,与业务没多大关系。「缓存雪崩」则是因为多个 KEY 同时失效,导致数据库请求太多。非热点数据也会导致缓存雪崩,只要同时失效的 KEY 足够多。

面对海量请求,缓存设计还应该考虑哪些问题?(转)相关推荐

  1. 从bitmap到布隆过滤器,再到高并发缓存设计策略

    点击关注公众号,Java干货及时送达 作者:that_is_cool blog.csdn.net/that_is_cool/article/details/91346356 前言:怎么能把风马牛不相及 ...

  2. 多级缓存设计详解 | 给数据库减负,刻不容缓!

    关注我们获得更多内容 作 者 简 介 王梓晨 物流研发部架构师,GIS 技术部负责人,2012 年加入京东,多年一线团队大促备战经验,负责物流研发一些部门的架构工作,专注于低延迟系统设计与海量数据处理 ...

  3. 阿里云发布黑科技:面对海量的文本翻译任务,阿里翻译团队是如何解决的

    对国际化企业来说语言问题是亟待突破的重要关口.面对海量的文本翻译任务,昂贵低效的人工翻译显然不能满足需求,利用计算机自动进行文本翻译的机器翻译才是解决这个问题的关键.阿里翻译团队在机器翻译领域做了大量 ...

  4. 黑科技揭秘:面对海量的文本翻译任务,阿里翻译团队是如何解决的

    对国际化企业来说语言问题是亟待突破的重要关口.面对海量的文本翻译任务,昂贵低效的人工翻译显然不能满足需求,利用计算机自动进行文本翻译的机器翻译才是解决这个问题的关键.阿里翻译团队在机器翻译领域做了大量 ...

  5. 分布式技术与实战第六课 分布式缓存设计

    第33讲:不止业务缓存,分布式系统中还有哪些缓存? 缓存是分布式系统开发中的常见技术,在分布式系统中的缓存,不止 Redis.Memcached 等后端存储:在前端页面.浏览器.网络 CDN 中也都有 ...

  6. SpringCloud Alibaba实战第八课 缓存设计、网关认证、重构策略

    19 性能为王:微服务架构中的多级缓存设计 前一讲我们学习了利用 Seata 构建微服务环境的分布式事务架构,通过完整的案例也了解了 Seata 的执行过程. 本讲咱们探讨缓存这个话题,看在微服务环境 ...

  7. 黑科技揭秘:面对海量的文本翻译任务,阿里翻译团队是如何解决的 1

    摘要: 对国际化企业来说语言问题是亟待突破的重要关口.面对海量的文本翻译任务,昂贵低效的人工翻译显然不能满足需求,利用计算机自动进行文本翻译的机器翻译才是解决这个问题的关键.阿里翻译团队在机器翻译领域 ...

  8. 面向海量服务的设计原则和策略总结

    http://www.blogjava.net/caizh2009/archive/2010/05/28/322167.html 互联网服务的特点就是面向海量级的用户,面向海量级的用户如何提供稳定的服 ...

  9. iOS缓存设计(YYCache思路)

    iOS缓存设计(YYCache思路) 前言: 前段时间业务有缓存需求,于是结合YYCache和业务需求,做了缓存层(内存&磁盘)+ 网络层的方案尝试 由于YYCache 采用了内存缓存和磁盘缓 ...

最新文章

  1. linux进不了容器配置目录,linux – 在Docker容器中使用bcrypt的ELF头文件或安装问题...
  2. 设计中色彩的注意事项有哪些
  3. edusoho linux 500错误,EduSoho网校系统如何处理500 Internal Server Error? - EduSoho官网
  4. 华为与美国公司就授权5G平台展开初期谈判;Linux 中存在严重漏洞;Microsoft 发布 Cosmos DB GA 版……...
  5. Unity Shader:用几何着色器实现复联3灭霸的终极大招灰飞烟灭
  6. c语言五个整数排列,刚学c语言,老师让用if编一个五个数字从大到小的排序,有那个大神能帮我,谢谢啦...
  7. php 放大镜代码,jQuery实现放大镜效果实例代码_jquery
  8. C++相对于C语言更加规范(1)
  9. Matlab2012b license失效解决办法
  10. vb.net中如何结束一个线程
  11. Shiro 权限验证原理
  12. 关于Euler-Poisson积分的几种解法
  13. 现有的 NFT 协议
  14. 电脑如何修改图片尺寸大小?怎么图片改大小?
  15. IT耳朵IT桔子:2017年人工智能行业发展研究报告白皮书
  16. 深入理解自编码器(用变分自编码器生成图像)
  17. Vue Echarts英文版地图——强大的高德地图
  18. 安装依赖总是报错Install fail! Error: EBUSY: resource busy or locked
  19. 《惢客创业日记》2018.11.02(周五) “追梦大叔”的回忆
  20. 美国通胀再创新高,一夜梦回八零年代

热门文章

  1. 蓝桥杯 ALGO-42 算法训练 送分啦
  2. 全国计算机二级C 错题/知识点整理
  3. AIX 查看进程列表
  4. JSON与MAP之间的转换
  5. 小米运维—互联网企业级监控系统实践
  6. 洛谷P1962 斐波那契数列
  7. 4-5 求自定类型元素的最大值 (10分)
  8. spring配置 quartz-config.xml
  9. TURBOMAIL邮件服务器—挽救错误邮件
  10. 中兴V880使用手记之二——取得root权限