你好呀,我是歪歪。
是这样的,前几天有个读者给我发音讯,说面试的时分遇到一个场景题:
他说他事先,一时间居然找不到回答成绩的角度,觉得本人没有回答到点子上。
我细心想了一下,确实是感到这个成绩有一丝丝的奇异,有一种让人千言万语,又突然懵逼不知从何说起的神奇力气。
为什么这么说呢?
我们先读题啊,细心的读一遍题,我给你翻译一下。
假设线上 Redis 挂了。然后一切央求打到数据库招致数据库也挂了。
这是啥?
Redis 挂了,不就是缓存都没了吗?
缓存都没了,不就是缓存雪崩了吗?
缓存雪崩了,不就招致数据库挂了吗?
一提到“缓存雪崩”这四个字,缓存穿透、缓存击穿这几兄弟,是不是就立马条件反射的出如今你的脑海外面了,还顺带着对应的几套处置方案。
然后就像背书似的,什么缓存全没了,什么缓存没有数据库中有,什么缓存和数据库中都没有...
张口就是几分钟不带停顿的。
另外关于缓存击穿缓和存穿透,很多同窗都会搞混。
你换一个记法,缓存拆穿、缓存戳透。
穿,只是穿过了缓存。
透,是直接干究竟。
你细品,应该就不会记混。
除了下面的“Redis 缓存三连击”这一套八股文之外,还隐藏着另外一个八股文:
Redis 挂了,为什么挂了?怎样就挂了?是不是有单点成绩?
这不就是问你 Redis 效劳的高可用吗?
说到 Redis 的高可用,脑子外面必须马上蹦出来主从、哨兵和集群吧?
想到这些了,张口又是几分钟不带停顿的。
但是这几分钟的千言万语,马上就被下面这个成绩给干懵逼了?
这时该怎样停止恢复?
如今问你怎样恢复,就是事中的事儿了。
你得先说怎样恢复,再说怎样预防。
你要是下去就回答前面说的什么“缓存三连击”、“高可用架构”,还包括大少数同窗能想到的多级缓存、限流措施、效劳升级、熔断机制,这些都有点牵强。
由于毕竟这些手腕都是事前的预防措施,下去就说这些背书痕迹比较清楚。
答一定是要答的,从事中恢复过度到事前预防方案,而且重点就是事前预防,那么我们怎样过度的自然一点呢?
先说事中怎样恢复,其实我觉得几句话就说完了。
效劳挂了啊,老哥,还能怎样恢复,当然是重启效劳啊。
站在运维人员的角度,当然优先思索是先把 Redis 和数据库效劳重新启动起来啦。
但是启动之前得先做个小操作,把流量摘掉,可以先把流量阻拦在入口的中央,比如复杂粗犷的经过 Nginx 的配置把央求都转到一个精心设计的错误页面,就是说这么一个意思。
这样做的目的是为了避免流量过大,直接把新启动的效劳,启动一个打挂一个的状况出现。
要是启动起来又扛不住了,请在心里默念散布式系统三大利器:
不行就加钱,堆机器嘛。
要觉得堆机器没啥技术含量,你就再从缓存预热的角度答一个。
就是当 Redis 效劳重新启动后,经进顺序先放点已知的热点 key 出来后,系统再对外提供效劳,避免缓存击穿的场景。
而且下面这一系列操作其实和开发人员的关系不大,主要是运维同窗干的事儿。
开发同窗最多就是在设计效劳的时分做到效劳有形状,以到达快速水平扩容的目的。
至于怎样去快速水平扩容,那是运维同窗的事儿,暂时不要去抢别人的饭碗。
答到这,你就可以用“但是”来过度到事前预防,末尾本人的表演了。
故作沉思的对面试官说“but”了:
我觉得从技术方案的角度来说,我们应该做到事前预防。
这一切的成绩都是由于 Redis 崩了,也就是发作了缓存雪崩。
在高并发的状况下,除了缓存雪崩,我们还必须得思索到缓存的击穿、穿透成绩。
而且 Redis 为什么会崩了?是不是运用姿态不对?是不是没有保证高可用?
效劳中是不是需求思索限流或许熔断机制,最大水平的保护顺序的运转?
或许我们能否应该树立多级缓存的机制,避免 Redis 挂掉之后,大批流量直接打到 MySQL 效劳招致数据库的崩盘?
至此,“but”完成,答题的方向从事中恢复,转向了事前预防,进入了我们的强项,八股文专场,然后就可以末尾“背诵”了。
我这里复杂的聊一下缓存成绩三连击和 Redis 的高可用。
至于多级缓存,可以看看我之前发的这篇文章:《这波舒适了,落地多级缓存!》。
缓存击穿先说一下缓存击穿的概念。
缓存击穿是指一个央求要拜访的数据,缓存中没有,但数据库中有的状况。
这种状况普通来说就是缓存过时了。
但是这时由于并发拜访这个缓存的用户特别多,这是一个热点 key,这么多用户的央求同时过去,在缓存外面没有取到数据,所以又同时去拜访数据库取数据,惹起数据库流量激增,压力瞬间增大,直接崩溃给你看。
所以一个数据有缓存,每次央求都从缓存中快速的前往了数据,但是某个时间点缓存失效了,某个央求在缓存中没有央求到数据,这时分我们就说这个央求就"击穿"了缓存。
针对这个场景,对应的处置方案普通来说有三种。
第一个就是只放行一个央求到数据库,然后做构建缓存的操作。
多个央求只放行一个,怎样做?
就借助 Redis setNX 命令设置一个标志位就行。设置成功的放行,设置失败的就轮询等候。
第二个处置方案就是后台续命。
这个方案的思想就是,后台开一个定时义务,专门自动更新行将过时的数据。
比如顺序中设置 why 这个热点 key 的时分,同时设置了过时时间为 10 分钟,那后台顺序在第 8 分钟的时分,会去数据库查询数据并重新放到缓存中,同时再次设置缓存为 10 分钟。
怎样样,是不是有点 Redisson 散布式锁看门狗的滋味?
我觉得思想是一脉相承的。
只是方案落地的时分,从代码编写的角度来说稍微费事了一点。
我曾经也借助这个思想开发过一个流水号系统。
大约是这样的。
流水号系统,属于十分关键的系统,为了降低数据库异常对效劳带来的冲击,所以效劳启动后会就会为每种业务系统都预先在缓存中缓存 5000 个流水号。
然后后台 Job 定时反省缓存中还剩下多少流水号,假设小于 1000 个,则再预先生成新的流水号,补充到缓存中,让缓存中的流水号再次回到 5000 个。
这样做的益处就是数据库异常后,我至少保证还有 5000 个缓存可以保证下游业务,我有一定的时间去恢双数据库。
这也算是一种后台续命的思想。
第三个办法就复杂了:永不过时。
缓存为什么会被击穿,是不是由于设置了超时时间,然后被回收了?
那我不设置超时时间不就行了?
假设结合实践场景你用脚趾头都能想到这个 key 一定会是个热点 key,会有少量的央求来拜访这个数据。而且这个 key 对应的 value 不会发作变化。
关于这样的数据你还设置过时时间干什么?
直接放出来,永不过时。
其实下面的后台续命思想的最终表现是也是永不过时。
只是后台续命的思想,会自动更新缓存,适用于缓存会变的场景。会出现缓存不分歧的状况,取决于你的业务场景能接受多长时间的缓存不分歧。
总之,详细状况,详细剖析。
但是思绪要明晰,最终方案都是常规方案的组合或许变种。
缓存穿透那么啥又是缓存穿透呢?
缓存穿透是指一个央求要拜访的数据,缓存和数据库中都没有,而用户短时间、高密度的发起这样的央求,每次都打到数据库效劳上,给数据库形成了压力。
普通来说这样的央求属于恶意央求。
就比如说,我这是一个技术群众号,你明明知道我没有,但是你非要来我这里买一瓶啤酒,恶意央求。
怎样处置呢?
两个方案。
第一个缓存空对象。
就是在数据库即使没有查询到数据,我们也把这次央求当做 key 缓存起来,value 可以是 NULL。
下次异样央求就会命中这个 NULL,缓存层就处置了这个央求,不会对数据库产生压力。
这样完成起来复杂,开发成本很低。
但这样随之而来的一个面试题必需要留意一下:
关于恶意攻击,央求的时分key往往各不相反,且只央求一次,那你要把这些 key 都缓存起来的话,由于每个 key 都只央求一次,那还是每次都会央求数据库,没有保护到数据库呀?
这个成绩,布隆过滤器,了解一下?
关于布隆过滤器我之前写过这篇文章,可以看看:《布隆,牛逼!布谷鸟,牛逼!》
布隆过滤器的特性是说某个值存在时,这个值能够不存在。当它说不存在时,那就一定不存在。
所以可以基于这个特性,把已有数据都构建到布隆过滤器外面去。
然后它可以帮忙挡住绝大部分的攻击。
但是还有个比较容易无视的连环炮成绩:
面试官:布隆过滤器容量有限且不支持删除,随着外面内容的添加,误判率就会随之上升。请问,这个成绩你们是怎样处置的?
也是两个答题方向。
首先,不支持删除的话,就换一个支持删除的布隆过滤器的轮子咯。
比如我前面的文章中提到的布谷鸟过滤器。
或许就是提早重构布隆过滤器。
比如在容量到达 50% 的时分,就央求一个新的更大的布隆过滤器来交流掉之前的过滤器。
只是需求留意的是,重建你得知道有那些数据需求停止重建的,所以你得有个中央来记载。
比如就是 Redis、数据库,甚至内存缓存都可以。
衰败地过没关系,你底气十足的回答就行了。
你要置信,面试官八成也衰败地过,你们看的说不定都是同一份材料呢。
缓存雪崩缓存雪崩是指缓存中大少数的数据在同一时间抵达过时时间,而查询数据量庞大,这时分,又是缓存中没有,数据库中有的状况了。
央求都打到数据库上,惹起数据库流量激增,压力瞬间增大,直接崩溃给你看。
和前面讲的缓存击穿不同的是,缓存击穿指少量的央求并发查询同一条数据。
缓存雪崩是不同数据都到了过时时间,招致这些数据在缓存中都查询不到,
雪崩,还是用的很笼统的。
避免雪崩的方案复杂来说就是错峰过时。
在设置 key 过时时间的时分,在加上一个短的随机过时时间,这样就能避免少量缓存在同一时间过时,惹起的缓存雪崩。
假设发了雪崩,我们可以有效劳升级、熔断、限流手腕来拒绝一些央求,保证效劳的正常。
但是,这些对用户体验是有一定影响的。假定我们的顺序有这的逻辑,也是拿来兜底的,从用户的角度来说,是不希望走到这样的逻辑中去。
所以,还是以预防雪崩为主。
最后还有一种雪崩,就是整个 Redis 效劳都挂了。
所以,接上去就要聊聊 Redis 效劳的高可用架构了。
Redis 高可用架构聊到 Redis 高可用架构,大家基本上都能想到主从、哨兵、集群这三种形式。
主从结构很复杂,就不说了,其弊端主要是出现缺点的时分需求人工介入干预,需求人工介入的,就不是真正的高可用。
哨兵和集群这两种是写在官网上的方案:
https://redis.io/topics/introduction
(责任编辑:admin)