乐趣区

关于java:Redis挂了流量把数据库也打挂了怎么办

你好呀,我是歪歪。

是这样的,前几天有个读者给我发音讯,说面试的时候遇到一个场景题:

他说他过后,一时间居然找不到答复问题的角度,感觉本人没有答复到点子上。

我认真想了一下,的确是感到这个问题有一丝丝的奇怪,有一种让人一言半语,又忽然懵逼不知从何说起的神奇力量。

为什么这么说呢?

咱们先读题啊,认真的读一遍题,我给你翻译一下。

如果线上 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/intro…

下面划线的话翻译过去就是:Redis 通过 Redis 哨兵(Sentinel)和 Cluster 集群提供高可用性(high availability)。

其中,哨兵是官网举荐的高可用计划(official high availability solution):

所以次要说一下哨兵模式。

哨兵是用来治理多个 Redis 服务器的,我从《Redis 开发与运维》一书中,拍个照片给你看看:

它次要执行三种类型的工作:

  • 监控(Monitoring):Sentinel 会一直地查看你的主服务器和从服务器是否运作失常。
  • 揭示(Notification):当被监控的某个 Redis 服务器呈现问题时,Sentinel 能够通过 API 向管理员或者其余应用程序发送告诉。
  • 主动故障迁徙(Automatic failover):当一个主服务器不能失常工作时,Sentinel 会开始一次主动故障迁徙操作,它会将生效主服务器的其中一个从服务器降级为新的主服务器,并让生效主服务器的其余从服务器改为复制新的主服务器;当客户端试图连贯生效的主服务器时,集群也会向客户端返回新主服务器的地址,使得集群能够应用新主服务器代替生效服务器。

哨兵其实也是一个分布式系统,咱们能够运行多个哨兵。

而后这些哨兵之间须要互相通气,交流信息,通过投票来决定是否执行主动故障迁徙,以及抉择哪个从服务器作为新的主服务器。

哨兵之间采纳的协定是 gossip,是一种去中心化的协定,达成的是最终一致性,十分有意思,

之前写过的凤凰架构外面有对于 gossip 协定的介绍,能够看看:

https://icyfenix.cn/distribut…

另外,如果主节点挂了,哨兵到底通过什么规定抉择新的主节点,也就是选举过程大抵是怎么样的,也偶现于面试环节。

我以前就被问到过,幸好过后背的纯熟。

简略说一下规定,无它,背诵就完事了:

  • 在挂了的主节点下挂的从节点中,被标记为主观下线、已断线、或者最初一次回复 PING 命令的工夫大于五秒钟的从节点都没有资格参加选举。
  • 在挂了的主节点下挂的从节点中,那些与挂了的主节点连贯断开的时长超过 down-after 配置指定的时长十倍的从节点都没有资格参加选举。
  • 通过下面这两轮淘汰之后,剩下来的从服务器中,选出复制偏移量(replication offset)最大的那个从服务器作为新的主服务器。如果复制偏移量不可用,或者从服务器的复制偏移量雷同,那么带有最小运行 ID 的那个从服务器成为新的主服务器。

其实执行下面这些操作的,是一个哨兵。而咱们的哨兵个别是三个以上,那么那个哨兵来执行这些操作呢?

其实这个哨兵也是须要从多个哨兵中被选举一个进去的,被选出来的这个哨兵就是领头哨兵 (leader Sentinel)。

选举领头哨兵的时候,采取的是 Raft 算法。

至于哨兵模式的搭建,一般来说是运维干的事儿。

然而网上的搭建教程很多,能本人跟着教程亲自搭一波那就更好了。

置信我,搭建的过程中你肯定会碰到各种各样的问题,而这些问题就是你的播种。

回到开始

这一大节,咱们回到最开始的这个面试题:

其实看到这个问题的时候,我就想到了老是被爆来爆去的微博。

刚好,这周又吃了一波吴某凡的瓜,过后还正在看女排的直播,看到报道的时候,表情大略是这样的:

.png)

周六的早晨基本上就是带着这个表情瓜田外面上蹿下跳的,真是太好吃了。

然而凡凡这一波,不晓得是凡凡的流量不行了,还是微博的架构禁受住了考验。

微博居然还比拟顺滑,没有呈现大范畴的、非常明显的服务挂掉的景象。

我印象中最近一次微博挂的死死的,就是鹿晗关晓彤那事了。

倒不是因为我关注他们,而是我关注到了那天正在结婚的程序员。

要说这位丁振凯同学也真是太惨了。

结婚的时候碰上鹿晗颁布恋情。海内度假时撞上双宋官宣。老婆待产的时候撞上华晨宇抵赖和张碧晨未婚生有一女。

这次我去看了,体现比拟淡定。应该是在一手抱娃,一手扩容,顺便吃瓜。

当年鹿晗这事,微博助手说挂掉是因为单条微博转发、评论次数太多了。

这是不全面的,单纯的转发评论多,并不能压垮大微博。而且鹿晗的那天微博应该也不是他所以的微博中转发评论最多的一条。

是因为转发、评论并发太高太高太高了,是我一辈子都接触不到的霎时流量。

吃瓜大众也一拥而上,短时间内同时在线迅速爆涨,把服务器干掉了:

对于这个问题,我在知乎上看到一个评论,我感觉挺好的,搬运截图一下:

https://www.zhihu.com/questio…

你看,这个场景和面试官问的问题是不是有点类似?

强如微博,也是加了 1000 台服务器来应答这次流量洪峰。

所以,服务挂了怎么办?

重启。

重启还不行怎么办?

加钱,扩机器。

要是鹿晗关晓彤事件,驰名狗仔卓伟能提前爆个料,打个提前量。

兴许,微博就能抵制的住那一波流量洪峰。

要是吴签这事,北京警方能和微博提前统统气,在公布之前先告诉一下微博的相干人员,哪怕提前 10 分钟呢?

兴许,就有更多的人能顺畅丝滑的吃瓜。

最初说一句(求关注)

好了,看到了这里安顿个关注吧,周更很累的,须要一点正反馈。

感谢您的浏览,我保持原创,非常欢送并感谢您的关注。

退出移动版