什么是缓存击穿?
缓存击穿、缓存并发和缓存雪崩是常见的由于并发量大而导致的缓存问题,本节讲解其产生原因和解决方案。
缓存击穿通常是由恶意攻击或者无意造成的;缓存并发是由设计不足造成的;缓存雪崩是由缓存同时失效造成的,三种问题都比较典型,也是难以防范和解决的。本节给出通用的解决方案,以供在缓存设计的过程中参考和使用。
缓存击穿
缓存击穿指的是使用不存在的key进行大量的高并发查询,这导致缓存无法命中,每次请求都要击穿到后端数据库系统进行查询,使数据库压力过大,甚至使数据库服务被压死。
我们通常将空值缓存起来,再次接收到同样的查询请求时,若命中缓存并且值为空,就会直接返回,不会透传到数据库,避免缓存击穿。当然,有时恶意袭击者可以猜到我们使用了这种方案,每次都会使用不同的参数来查询,这就需要我们对输入的参数进行过滤,例如,如果我们使用ID进行查询,则可以对ID的格式进行分析,如果不符合产生ID的规则,就直接拒绝,或者在ID上放入时间信息,根据时间信息判断ID是否合法,或者是否是我们曾经生成的ID,这样可以拦截一定的无效请求。
当然,每个设计人员都应该对服务的可用性和健壮性负责,应该建设健壮的服务,让我们的服务像不倒翁一样,因此,我们需要对服务设计限流和熔断等功能,请参考《分布式服务架构:原理、设计与实战》中第1章关于微服务设计模式的内容。
缓存并发
缓存并发的问题通常发生在高并发的场景下,当一个缓存key过期时,因为访问这个缓存key 的请求量较大,多个请求同时发现缓存过期,因此多个请求会同时访问数据库来查询最新数据,并且回写缓存,这样会造成应用和数据库的负载增加,性能降低,由于并发较高,甚至会导致数据库被压死。
我们通常有3种方式来解决这个问题。
分布式锁
使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。
本地锁
与分布式锁类似,我们通过本地锁的方式来限制只有一个线程去数据库中查询数据,而其他线程只需等待,等前面的线程查询到数据后再访问缓存。但是,这种方法只能限制一个服务节点只有一个线程去数据库中查询,如果一个服务有多个节点,则还会有多个数据库查询操作,也就是说在节点数量较多的情况下并没有完全解决缓存并发的问题。
软过期
软过期指对缓存中的数据设置失效时间,就是不使用缓存服务提供的过期时间,而是业务层在数据中存储过期时间信息,由业务程序判断是否过期并更新,在发现了数据即将过期时,将缓存的时效延长,程序可以派遣一个线程去数据库中获取最新的数据,其他线程这时看到延长了的过期时间,就会继续使用旧数据,等派遣的线程获取最新数据后再更新缓存。
也可以通过异步更新服务来更新设置软过期的缓存,这样应用层就不用关心缓存并发的问题了。
缓存雪崩
缓存雪崩指缓存服务器重启或者大量缓存集中在某一个时间段内失效,给后端数据库造成瞬时的负载升高的压力,甚至压垮数据库的情况。
通常的解决办法是对不同的数据使用不同的失效时间,甚至对相同的数据、不同的请求使用不同的失效时间,例如,我们要缓存user数据,会对每个用户的数据设置不同的缓存过期时间,可以定义一个基础时间,假设10秒,然后加上一个两秒以内的随机数,过期时间为10~12秒,就会避免缓存雪崩。
原文发布时间为:2018-07-22
本文作者:李艳鹏
本文来自云栖社区合作伙伴“程序员小灰”,了解相关信息可以关注“程序员小灰”

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
如何用1年时间获得3年成长?
前言 这世界存在这么一个银行,你一出生,就自动享有这家银行为你开设的一个 VIP 账号。每一天,这个 VIP 账号里面都会被自动存入不多不少恰好 86400 元钱。而你的任务就是每天都要把这 86400 元花光,随便你买什么。如果不够了,那就只能忍痛割爱——因为没办法,银行会告诉你,对不起,您只能等明天再来取下一笔 86400 元钱了。如果竟然没花完剩下了,就只好作废——因为没办法,银行会告诉你,对不起,我们这家银行不接受存款,并且还要每日注销余额。反正,每天一共就有这 86400 元,不多不少。 这家银行叫做“时间”。 时间在这个世界对任何人长度都是相等的。每个人每天都只有 24 小时,每个人的每个小时都只有 60 分钟,每个人的每分钟都只有 60 秒,每人每天一共 86400 秒,无论你是谁你在何方我们都是一样的。 那么为什么你总是觉得时间不够用? 用塞内加的《论生命之短暂》中的一段话来形容再合适不过了:“如果一个人出海遇到狂风暴雨,被变换肆虐的风吹得团团转,你可能会觉得他航行了很远。其实航行得并不远,只是浮沉动荡的时间长而已。” 有时候并不是时间不够用,而是你的方向错了。你虽然花...
- 下一篇
如何带领平均入职2.6个月的新人,完成一次系统重构?
一、背景 我们旧版首页系统属于集中化设计:「全能类」FeedBase加main函数。基本上所有功能耦合在一起。每维护一行代码,必须异常谨慎,以免影响其它逻辑。在这里,先把大致背景给大家介绍一下:系统有6.6万行代码,首页逻辑的学习成本至少3个月;增加一个新feed类型工作量是7个工作日;首页扩展一个Tab工作量是约3周;没有完善的链路跟踪,线上Bug无从下手;首页目前服务端响应p95高达870ms;部分逻辑处于无人维护状态;…… 二、我们该怎么做 其实呢,思路「很」清晰——解耦模块,优化性能。 可是怎么去解耦、解耦成什么、如何优化性能?Java/Go/C……重写? 2018年2月,为了支持兄弟团队业务,首页输出了我们几乎全部的工程师。事实上,目前首页仅有三个工程师、一个实习生。最资深的员工入职只有6个月,其余基本新入职,平均入职2.6个月,且都没有大型项目维护经验。换句话说,全是新人。 以这种现状,我们怎么去重构? 大家都知道重构是一个高大上的事,每个人都很积极,每个人都想做好一些事。但大家之前都在做普通业务,面向PM开发侵染了太多底色。似乎快速完成功能、快速上线比什么都重要,似乎只有...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS关闭SELinux安全模块
- CentOS8编译安装MySQL8.0.19
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker安装Oracle12C,快速搭建Oracle学习环境