自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Redis掛了,流量把數(shù)據(jù)庫也打掛了,怎么辦?

開發(fā) 前端 Redis
Redis 掛了,不就是緩存都沒了嗎?緩存都沒了,不就是緩存雪崩了嗎?緩存雪崩了,不就導致數(shù)據(jù)庫掛了嗎?一提到“緩存雪崩”這四個字,緩存穿透、緩存擊穿這幾兄弟,是不是就立馬條件反射的出現(xiàn)在你的腦海里面了,還順帶著對應(yīng)的幾套解決方案。

你好呀,我是歪歪。

是這樣的,前幾天有個讀者給我發(fā)消息,說面試的時候遇到一個場景題:

他說他當時,一時間竟然找不到回答問題的角度,感覺自己沒有回答到點子上。

我仔細想了一下,確實是感到這個問題有一絲絲的奇怪,有一種讓人千言萬語,又突然懵逼不知從何說起的神奇力量。

為什么這么說呢?

我們先讀題啊,仔細的讀一遍題,我給你翻譯一下。

如果線上 Redis 掛了。然后所有請求打到數(shù)據(jù)庫導致數(shù)據(jù)庫也掛了。

這是啥?

Redis 掛了,不就是緩存都沒了嗎?

緩存都沒了,不就是緩存雪崩了嗎?

緩存雪崩了,不就導致數(shù)據(jù)庫掛了嗎?

一提到“緩存雪崩”這四個字,緩存穿透、緩存擊穿這幾兄弟,是不是就立馬條件反射的出現(xiàn)在你的腦海里面了,還順帶著對應(yīng)的幾套解決方案。

然后就像背書似的,什么緩存全沒了,什么緩存沒有數(shù)據(jù)庫中有,什么緩存和數(shù)據(jù)庫中都沒有...

張口就是幾分鐘不帶停頓的。

另外關(guān)于緩存擊穿和緩存穿透,很多同學都會搞混。

你換一個記法,緩存戳穿、緩存戳透。

穿,只是穿過了緩存。

透,是直接干到底。

你細品,應(yīng)該就不會記混。

除了上面的“Redis 緩存三連擊”這一套八股文之外,還隱藏著另外一個八股文:

Redis 掛了,為什么掛了?怎么就掛了?是不是有單點問題?

這不就是問你 Redis 服務(wù)的高可用嗎?

說到 Redis 的高可用,腦子里面必須馬上蹦出來主從、哨兵和集群吧?

想到這些了,張口又是幾分鐘不帶停頓的。

但是這幾分鐘的千言萬語,馬上就被下面這個問題給干懵逼了?

這時該怎么進行恢復?

現(xiàn)在問你怎么恢復,就是事中的事兒了。

你得先說怎么恢復,再說怎么預(yù)防。

你要是上來就回答前面說的什么“緩存三連擊”、“高可用架構(gòu)”,還包括大多數(shù)同學能想到的多級緩存、限流措施、服務(wù)降級、熔斷機制,這些都有點牽強。

因為畢竟這些手段都是事前的預(yù)防措施,上來就說這些背書痕跡比較明顯。

答肯定是要答的,從事中恢復過度到事前預(yù)防方案,而且重點就是事前預(yù)防,那么我們怎么過度的自然一點呢?

先說事中怎么恢復,其實我覺得幾句話就說完了。

服務(wù)掛了啊,老哥,還能怎么恢復,當然是重啟服務(wù)啊。

站在運維人員的角度,當然優(yōu)先考慮是先把 Redis 和數(shù)據(jù)庫服務(wù)重新啟動起來啦。

但是啟動之前得先做個小操作,把流量摘掉,可以先把流量攔截在入口的地方,比如簡單粗暴的通過 Nginx 的配置把請求都轉(zhuǎn)到一個精心設(shè)計的錯誤頁面,就是說這么一個意思。

這樣做的目的是為了防止流量過大,直接把新啟動的服務(wù),啟動一個打掛一個的情況出現(xiàn)。

要是啟動起來又扛不住了,請在心里默念分布式系統(tǒng)三大利器:

[[416618]]

不行就加錢,堆機器嘛。

要覺得堆機器沒啥技術(shù)含量,你就再從緩存預(yù)熱的角度答一個。

就是當 Redis 服務(wù)重新啟動后,通過程序先放點已知的熱點 key 進去后,系統(tǒng)再對外提供服務(wù),防止緩存擊穿的場景。

而且上面這一系列操作其實和開發(fā)人員的關(guān)系不大,主要是運維同學干的事兒。

開發(fā)同學最多就是在設(shè)計服務(wù)的時候做到服務(wù)無狀態(tài),以達到快速水平擴容的目的。

至于怎么去快速水平擴容,那是運維同學的事兒,暫時不要去搶別人的飯碗。

答到這,你就可以用“但是”來過度到事前預(yù)防,開始自己的表演了。

故作沉思的對面試官說“but”了:

[[416619]]

我覺得從技術(shù)方案的角度來說,我們應(yīng)該做到事前預(yù)防。

這一切的問題都是因為 Redis 崩了,也就是發(fā)生了緩存雪崩。

在高并發(fā)的情況下,除了緩存雪崩,我們還必須得考慮到緩存的擊穿、穿透問題。

而且 Redis 為什么會崩了?是不是使用姿勢不對?是不是沒有保證高可用?

服務(wù)中是不是需要考慮限流或者熔斷機制,最大程度的保護程序的運行?

或者我們是否應(yīng)該建立多級緩存的機制,防止 Redis 掛掉之后,大批流量直接打到 MySQL 服務(wù)導致數(shù)據(jù)庫的崩盤?

至此,“but”完成,答題的方向從事中恢復,轉(zhuǎn)向了事前預(yù)防,進入了我們的強項,八股文專場,然后就可以開始“背誦”了。

我這里簡單的聊一下緩存問題三連擊和 Redis 的高可用。

至于多級緩存,可以看看我之前發(fā)的這篇文章:《這波舒服了,落地多級緩存!》。

緩存擊穿

先說一下緩存擊穿的概念。

緩存擊穿是指一個請求要訪問的數(shù)據(jù),緩存中沒有,但數(shù)據(jù)庫中有的情況。

這種情況一般來說就是緩存過期了。

但是這時由于并發(fā)訪問這個緩存的用戶特別多,這是一個熱點 key,這么多用戶的請求同時過來,在緩存里面沒有取到數(shù)據(jù),所以又同時去訪問數(shù)據(jù)庫取數(shù)據(jù),引起數(shù)據(jù)庫流量激增,壓力瞬間增大,直接崩潰給你看。

所以一個數(shù)據(jù)有緩存,每次請求都從緩存中快速的返回了數(shù)據(jù),但是某個時間點緩存失效了,某個請求在緩存中沒有請求到數(shù)據(jù),這時候我們就說這個請求就"擊穿"了緩存。

針對這個場景,對應(yīng)的解決方案一般來說有三種。

第一個就是只放行一個請求到數(shù)據(jù)庫,然后做構(gòu)建緩存的操作。

多個請求只放行一個,怎么做?

就借助 Redis setNX 命令設(shè)置一個標志位就行。設(shè)置成功的放行,設(shè)置失敗的就輪詢等待。

第二個解決方案就是后臺續(xù)命。

這個方案的思想就是,后臺開一個定時任務(wù),專門主動更新即將過期的數(shù)據(jù)。

比如程序中設(shè)置 why 這個熱點 key 的時候,同時設(shè)置了過期時間為 10 分鐘,那后臺程序在第 8 分鐘的時候,會去數(shù)據(jù)庫查詢數(shù)據(jù)并重新放到緩存中,同時再次設(shè)置緩存為 10 分鐘。

怎么樣,是不是有點 Redisson 分布式鎖看門狗的味道?

我覺得思想是一脈相承的。

只是方案落地的時候,從代碼編寫的角度來說稍微麻煩了一點。

我曾經(jīng)也借助這個思想開發(fā)過一個流水號系統(tǒng)。

大概是這樣的。

流水號系統(tǒng),屬于非常關(guān)鍵的系統(tǒng),為了降低數(shù)據(jù)庫異常對服務(wù)帶來的沖擊,所以服務(wù)啟動后會就會為每種業(yè)務(wù)系統(tǒng)都預(yù)先在緩存中緩存 5000 個流水號。

然后后臺 Job 定時檢查緩存中還剩下多少流水號,如果小于 1000 個,則再預(yù)先生成新的流水號,補充到緩存中,讓緩存中的流水號再次回到 5000 個。

這樣做的好處就是數(shù)據(jù)庫異常后,我至少保證還有 5000 個緩存可以保證上游業(yè)務(wù),我有一定的時間去恢復數(shù)據(jù)庫。

這也算是一種后臺續(xù)命的思想。

第三個方法就簡單了:永不過期。

緩存為什么會被擊穿,是不是因為設(shè)置了超時時間,然后被回收了?

那我不設(shè)置超時時間不就行了?

如果結(jié)合實際場景你用腳趾頭都能想到這個 key 一定會是個熱點 key,會有大量的請求來訪問這個數(shù)據(jù)。而且這個 key 對應(yīng)的 value 不會發(fā)生變化。

對于這樣的數(shù)據(jù)你還設(shè)置過期時間干什么?

直接放進去,永不過期。

其實上面的后臺續(xù)命思想的最終體現(xiàn)是也是永不過期。

只是后臺續(xù)命的思想,會主動更新緩存,適用于緩存會變的場景。會出現(xiàn)緩存不一致的情況,取決于你的業(yè)務(wù)場景能接受多長時間的緩存不一致。

總之,具體情況,具體分析。

但是思路要清晰,最終方案都是常規(guī)方案的組合或者變種。

緩存穿透

那么啥又是緩存穿透呢?

緩存穿透是指一個請求要訪問的數(shù)據(jù),緩存和數(shù)據(jù)庫中都沒有,而用戶短時間、高密度的發(fā)起這樣的請求,每次都打到數(shù)據(jù)庫服務(wù)上,給數(shù)據(jù)庫造成了壓力。

一般來說這樣的請求屬于惡意請求。

就比如說,我這是一個技術(shù)公眾號,你明明知道我沒有,但是你非要來我這里買一瓶啤酒,惡意請求。

怎么解決呢?

兩個方案。

第一個緩存空對象。

就是在數(shù)據(jù)庫即使沒有查詢到數(shù)據(jù),我們也把這次請求當做 key 緩存起來,value 可以是 NULL。

下次同樣請求就會命中這個 NULL,緩存層就處理了這個請求,不會對數(shù)據(jù)庫產(chǎn)生壓力。

這樣實現(xiàn)起來簡單,開發(fā)成本很低。

但這樣隨之而來的一個面試題必須要注意一下:

對于惡意攻擊,請求的時候key往往各不相同,且只請求一次,那你要把這些 key 都緩存起來的話,因為每個 key 都只請求一次,那還是每次都會請求數(shù)據(jù)庫,沒有保護到數(shù)據(jù)庫呀?

這個問題,布隆過濾器,了解一下?

關(guān)于布隆過濾器我之前寫過這篇文章,可以看看:《布隆,牛逼!布谷鳥,牛逼!》

布隆過濾器的特性是說某個值存在時,這個值可能不存在。當它說不存在時,那就肯定不存在。

所以可以基于這個特性,把已有數(shù)據(jù)都構(gòu)建到布隆過濾器里面去。

然后它可以幫忙擋住絕大部分的攻擊。

但是還有個比較容易忽視的連環(huán)炮問題:

面試官:布隆過濾器容量有限且不支持刪除,隨著里面內(nèi)容的增加,誤判率就會隨之上升。請問,這個問題你們是怎么解決的?

也是兩個答題方向。

首先,不支持刪除的話,就換一個支持刪除的布隆過濾器的輪子咯。

比如我前面的文章中提到的布谷鳥過濾器。

或者就是提前重構(gòu)布隆過濾器。

比如在容量達到 50% 的時候,就申請一個新的更大的布隆過濾器來替換掉之前的過濾器。

只是需要注意的是,重建你得知道有那些數(shù)據(jù)需要進行重建的,所以你得有個地方來記錄。

比如就是 Redis、數(shù)據(jù)庫,甚至內(nèi)存緩存都可以。

沒落地過沒關(guān)系,你底氣十足的回答就行了。

你要相信,面試官八成也沒落地過,你們看的說不定都是同一份資料呢。

緩存雪崩

緩存雪崩是指緩存中大多數(shù)的數(shù)據(jù)在同一時間到達過期時間,而查詢數(shù)據(jù)量巨大,這時候,又是緩存中沒有,數(shù)據(jù)庫中有的情況了。

請求都打到數(shù)據(jù)庫上,引起數(shù)據(jù)庫流量激增,壓力瞬間增大,直接崩潰給你看。

和前面講的緩存擊穿不同的是,緩存擊穿指大量的請求并發(fā)查詢同一條數(shù)據(jù)。

緩存雪崩是不同數(shù)據(jù)都到了過期時間,導致這些數(shù)據(jù)在緩存中都查詢不到,

雪崩,還是用的很形象的。

防止雪崩的方案簡單來說就是錯峰過期。

在設(shè)置 key 過期時間的時候,在加上一個短的隨機過期時間,這樣就能避免大量緩存在同一時間過期,引起的緩存雪崩。

如果發(fā)了雪崩,我們可以有服務(wù)降級、熔斷、限流手段來拒絕一些請求,保證服務(wù)的正常。

但是,這些對用戶體驗是有一定影響的。假設(shè)我們的程序有這的邏輯,也是拿來兜底的,從用戶的角度來說,是不希望走到這樣的邏輯中去。

所以,還是以預(yù)防雪崩為主。

最后還有一種雪崩,就是整個 Redis 服務(wù)都掛了。

所以,接下來就要聊聊 Redis 服務(wù)的高可用架構(gòu)了。

Redis 高可用架構(gòu)

聊到 Redis 高可用架構(gòu),大家基本上都能想到主從、哨兵、集群這三種模式。

主從結(jié)構(gòu)很簡單,就不說了,其弊端主要是出現(xiàn)故障的時候需要人工介入干預(yù),需要人工介入的,就不是真正的高可用。

哨兵和集群這兩種是寫在官網(wǎng)上的方案:

https://redis.io/topics/introduction

上面劃線的話翻譯過來就是:Redis 通過 Redis 哨兵(Sentinel)和 Cluster 集群提供高可用性(high availability)。

其中,哨兵是官方推薦的高可用方案(official high availability solution):

所以主要說一下哨兵模式。

哨兵是用來管理多個 Redis 服務(wù)器的,我從《Redis開發(fā)與運維》一書中,拍個照片給你看看:

它主要執(zhí)行三種類型的任務(wù):

  • 監(jiān)控(Monitoring): Sentinel 會不斷地檢查你的主服務(wù)器和從服務(wù)器是否運作正常。
  • 提醒(Notification): 當被監(jiān)控的某個 Redis 服務(wù)器出現(xiàn)問題時, Sentinel 可以通過 API 向管理員或者其他應(yīng)用程序發(fā)送通知。
  • 自動故障遷移(Automatic failover): 當一個主服務(wù)器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務(wù)器的其中一個從服務(wù)器升級為新的主服務(wù)器, 并讓失效主服務(wù)器的其他從服務(wù)器改為復制新的主服務(wù)器; 當客戶端試圖連接失效的主服務(wù)器時, 集群也會向客戶端返回新主服務(wù)器的地址, 使得集群可以使用新主服務(wù)器代替失效服務(wù)器。

哨兵其實也是一個分布式系統(tǒng),我們可以運行多個哨兵。

然后這些哨兵之間需要相互通氣,交流信息,通過投票來決定是否執(zhí)行自動故障遷移,以及選擇哪個從服務(wù)器作為新的主服務(wù)器。

哨兵之間采用的協(xié)議是 gossip,是一種去中心化的協(xié)議,達成的是最終一致性,非常有意思,

另外,如果主節(jié)點掛了,哨兵到底通過什么規(guī)則選擇新的主節(jié)點,也就是選舉過程大致是怎么樣的,也偶現(xiàn)于面試環(huán)節(jié)。

我以前就被問到過,幸好當時背的熟練。

簡單說一下規(guī)則,無它,背誦就完事了:

在掛了的主節(jié)點下掛的從節(jié)點中,被標記為主觀下線、已斷線、或者最后一次回復 PING 命令的時間大于五秒鐘的從節(jié)點都沒有資格參與選舉。

在掛了的主節(jié)點下掛的從節(jié)點中,那些與掛了的主節(jié)點連接斷開的時長超過 down-after 配置指定的時長十倍的從節(jié)點都沒有資格參與選舉。

經(jīng)過上面這兩輪淘汰之后,剩下來的從服務(wù)器中,選出復制偏移量(replication offset)最大的那個從服務(wù)器作為新的主服務(wù)器。如果復制偏移量不可用,或者從服務(wù)器的復制偏移量相同,那么帶有最小運行 ID 的那個從服務(wù)器成為新的主服務(wù)器。

其實執(zhí)行上面這些操作的,是一個哨兵。而我們的哨兵一般是三個以上,那么那個哨兵來執(zhí)行這些操作呢?

其實這個哨兵也是需要從多個哨兵中被選舉一個出來的,被選出來的這個哨兵就是領(lǐng)頭哨兵(leader Sentinel)。

選舉領(lǐng)頭哨兵的時候,采取的是 Raft 算法。

至于哨兵模式的搭建,一般來說是運維干的事兒。

但是網(wǎng)上的搭建教程很多,能自己跟著教程親自搭一波那就更好了。

相信我,搭建的過程中你一定會碰到各種各樣的問題,而這些問題就是你的收獲。

回到開始

這一小節(jié),我們回到最開始的這個面試題:

其實看到這個問題的時候,我就想到了老是被爆來爆去的微博。

剛好,這周又吃了一波吳某凡的瓜,當時還正在看女排的直播,看到報道的時候,表情大概是這樣的:

[[416623]]

周六的晚上基本上就是帶著這個表情瓜田里面上躥下跳的,真是太好吃了。

但是凡凡這一波,不知道是凡凡的流量不行了,還是微博的架構(gòu)經(jīng)受住了考驗。

微博竟然還比較順滑,沒有出現(xiàn)大范圍的、非常明顯的服務(wù)掛掉的現(xiàn)象。

我印象中最近一次微博掛的死死的,就是鹿晗關(guān)曉彤那事了。

倒不是因為我關(guān)注他們,而是我關(guān)注到了那天正在結(jié)婚的程序員。

要說這位丁振凱同學也真是太慘了。

結(jié)婚的時候碰上鹿晗公布戀情。海外度假時撞上雙宋官宣。老婆待產(chǎn)的時候撞上華晨宇承認和張碧晨未婚生有一女。

這次我去看了,表現(xiàn)比較淡定。應(yīng)該是在一手抱娃,一手擴容,順便吃瓜。

當年鹿晗這事,微博助手說掛掉是因為單條微博轉(zhuǎn)發(fā)、評論次數(shù)太多了。

這是不全面的,單純的轉(zhuǎn)發(fā)評論多,并不能壓垮大微博。而且鹿晗的那天微博應(yīng)該也不是他所以的微博中轉(zhuǎn)發(fā)評論最多的一條。

是因為轉(zhuǎn)發(fā)、評論并發(fā)太高太高太高了,是我一輩子都接觸不到的瞬間流量。

吃瓜群眾也蜂擁而至,短時間內(nèi)同時在線迅速爆漲,把服務(wù)器干掉了:

關(guān)于這個問題,我在知乎上看到一個評論,我覺得挺好的,搬運截圖一下:

https://www.zhihu.com/question/66346687

你看,這個場景和面試官問的問題是不是有點相似?

強如微博,也是加了 1000 臺服務(wù)器來應(yīng)對這次流量洪峰。

所以,服務(wù)掛了怎么辦?

重啟。

重啟還不行怎么辦?

加錢,擴機器。

要是鹿晗關(guān)曉彤事件,著名狗仔卓偉能提前爆個料,打個提前量。

也許,微博就能抵抗的住那一波流量洪峰。

要是吳簽這事,北京警方能和微博提前通通氣,在發(fā)布之前先通知一下微博的相關(guān)人員,哪怕提前10分鐘呢?

也許,就有更多的人能順暢絲滑的吃瓜。

責任編輯:未麗燕 來源: 今日頭條
相關(guān)推薦

2021-08-23 10:59:01

Nginx高可用Linux

2021-09-06 12:58:26

MQ面試數(shù)據(jù)庫

2021-10-03 15:00:44

數(shù)據(jù)庫mysql單機

2021-06-10 06:59:34

Redis應(yīng)用API

2020-12-16 08:11:21

服務(wù)supervisor進程

2020-12-01 10:32:42

Redis主從復制

2013-07-15 09:51:04

2023-03-21 23:57:35

2023-10-26 07:47:53

Redis哨兵集群

2021-01-05 10:48:38

RedisAOF日志RDB快照

2021-02-06 13:11:28

SQL系統(tǒng)數(shù)據(jù)庫

2019-10-12 09:50:46

Redis內(nèi)存數(shù)據(jù)庫

2024-07-31 08:21:53

2024-10-09 17:06:52

RedisHash哈希表

2023-10-25 08:01:30

redis主庫服務(wù)

2024-10-18 09:55:50

RedisHash數(shù)據(jù)

2011-08-29 15:58:58

2024-04-22 08:17:23

MySQL誤刪數(shù)據(jù)

2017-06-06 08:59:47

數(shù)字化轉(zhuǎn)型數(shù)據(jù)庫Go語言

2021-10-01 00:12:12

Redis分布式
點贊
收藏

51CTO技術(shù)棧公眾號