Redis快取穿透 快取雪崩 快取擊穿好好說說

2022-09-23 01:12:01 字數 3400 閱讀 7667

redis是目前非常流行的快取資料庫啦,其中一個主要作用就是為了避免大量請求直接打到資料庫,以此來緩解資料庫伺服器壓力;用上快取難道就高枕無憂了嗎?no,no,no,沒有這麼完美的技術, 快取穿透、快取雪崩、快取擊穿這些問題都得好好聊聊。

快取穿透是指查詢的資料在快取和資料庫中都不存在,導致每一次請求資料從快取中都獲取不到,而將請求打到資料庫伺服器,但資料庫中也沒有對應的資料,最後每一次請求都到資料庫;如果在高併發場景或有人惡意攻擊,就會導致後臺資料庫伺服器壓力增大,最終系統可能崩掉。來個直接點的圖:

簡要說明:

快取redis伺服器顏色說明:綠色塊代表有快取資料,粉色塊代表快取中沒有資料;綠色箭頭代表直接從快取中獲取資料;黃色箭頭代表穿過快取從資料庫中查資料,但不一定有。

流程大概如下:

大量客戶端發起大量請求到伺服器;

伺服器**邏輯將先經過快取,如果有快取資料(綠色部分),直接從快取中獲取資料資料返回;如果快取中沒有資料(粉色部分),請求就會直接打到資料庫伺服器(如黃色箭頭)。

如果存在大量無快取資料的請求,最終資料庫將因為過大壓力而崩掉,導致系統不可用。

瞅個圖先:

簡要說明:

將key進行多次hash計算;每次的hash演算法得到的結果都不一樣;上圖只畫了三次hash計算,其實實際根據誤判率不一樣,hash次數就不一樣;

將hash結果對應下標索引的bit位改為1,表示存在; 上圖經過三次hash,結果分別為2、5、9,則將對應的位置改為1;

如果需要判斷key是否在過濾器中,同樣需進行多次hash計算,上圖為三次,將計算出來的結果作為索引去獲取對應的標識,三次中只要有一次對應位置的值為0,那就證明key不存在過濾器中。 如果是判定存在,則三次的結果對應位置的值應該都為1,不過這樣是有誤判可能,因為不同的key,hash的結果有可能是一樣的,從而就導致設定對應索引位時就會有衝突,如下圖;先假設key1、key2經過三次hash的結果一樣(實際場景是存在的),倘若key1先來都將2、5、9位置的值設為1,那key2進來判斷存在時,由於hash的結果一樣,從而就誤判為在過濾器中,其實不存在;誤判率在布隆過濾器中是可以控制,如果需要降低誤判率,那就多進行幾次hash計算,那位置相同的概率就降低啦;但這樣會影響效率,另外也會有記憶體的額外開銷,hash次數多,需要標識的位就越多。 就算有誤判率,也很小,在絕大多數場景下可接受。

既然說redis,就說redis的布隆過濾器吧,其實小夥伴可以根據自己的需求利用redis的bitmap實現。那有沒有造好的輪子呢,當然有,在redis4.0開始就有一個布隆過濾器的元件,開箱即用,當然也有一些其他大佬封裝的,基於記憶體的,基於分散式都有。這裡簡單說說redis布隆過濾器的外掛,個人覺得挺好的,推薦哦。

我這面是用centos進行演示,主要步驟如下:

進入**目錄進行make(生成redisbloom.so檔案),如果make命令找不到,就需要安裝vc++編譯相關的包;cd redisbloom make

在redis配置檔案中配置載入redisbloom外掛,然後重啟就可以用啦;也可以啟動的時候指定載入外掛執行;配置檔案方式式:在配置檔案中新增如下配置,需要指定redisbloom.so具體的檔案位置。然後指定配置檔案啟動即可;./redis-server redis.conf 啟動時指定模組執行方式:./redis-server --loadmodule ./redisbloom.so

簡單使用命令使用和常規命令一樣啦,就不需要我再寫程式了吧,如果非要的話,那就簡單說兩句:a.將需要判斷資料儲存在過濾器中,比如所有的使用者id;b.當請求過來時就先從過濾器中判斷有無資料,沒有直接返回,不去快取,也不去資料庫;c.如果有新新增的使用者,需要將新的使用者id放到過濾器中;

關於redis布隆過濾器還有一些命令沒說,小夥伴可以去逛逛官網。有小夥伴說,不用這個外掛行嗎,當然行啊,可以自己實現嘛,不過有些小夥伴有封裝好的包啦,有基於記憶體的,也有基於redis的,如下圖:

**我就不上了,剩下的就留給小夥伴啦。

快取雪崩是指突然快取層不可用,導致大量請求直接打到資料庫,最終由於資料庫壓力過大可能導致系統崩掉。快取層不可用指以下兩方面:

如圖:

簡要說明:

快取redis伺服器顏色說明:綠色塊代表有快取資料,粉色塊代表快取中沒有資料;白色塊代表大範圍失效的快取資料,綠色箭頭代表直接從快取中獲取資料;黃色箭頭代表穿過快取從資料庫中查資料。

流程大概如下:

大量客戶端發起大量請求到伺服器;

伺服器**邏輯將先經過快取,如果有快取資料(綠色部分),直接從快取中獲取資料資料返回;如果快取過期(白色塊部分),請求就會直接打到資料庫伺服器(如黃色箭頭)。

如果存在大量熱資料的請求,但熱資料又大範圍過期,最終資料庫將因為過大壓力崩掉,導致系統不可用。

快取擊穿是指在超級熱點資料突然過期,導致針對超級熱點的資料請求在過期期間直接打到資料庫,這樣資料庫伺服器會因為某一超熱資料導致壓力過大而崩掉。

超熱資料:比如秒殺時的資料,某寶、某東、某多多這種平臺的資料如果在秒殺時間段失效,請求量足矣讓資料庫崩掉。

如圖:

簡要說明:

快取redis伺服器顏色說明:綠色塊代表有快取資料,粉色塊代表快取中沒有資料;白色圈代表超級熱點快取資料過期失效,綠色箭頭代表直接從快取中獲取資料;黃色箭頭代表穿過快取從資料庫中查資料。

流程大概如下:

大量客戶端發起大量請求到伺服器;

伺服器**邏輯將先經過快取,如果有快取資料(綠色部分),直接從快取中獲取資料資料返回;如果超熱快取資料過期(白色圈部分),請求就會直接打到資料庫伺服器(如黃色箭頭)。

超級熱點資料過期失效,如秒殺資料,如果在秒殺時段失效,最終資料庫將因為過大壓力崩掉,導致系統不可用。

注:這個只是針對超熱點資料,而不是大範圍資料。

快取穿透、快取雪崩、快取擊穿不管是哪個問題,其主要原因還是在快取層沒有命中,將請求直接打到資料庫啦,最終導致資料庫壓力過大,系統不可用。小夥伴根據系統需要進行問題處理,沒有完美的解決方案,但總會有一種適合需求的方案,解決業務問題才是真正目的。

今天沒有上**,相信小夥伴都能根據解決措施寫出對應的**,分散式鎖可能稍微有點難搞,下次抽時間給大家安排上。

關於redis系列,下篇說說lua指令碼就算初步完成啦,剩下的就是實戰的總結啦,在專案的使用過程中,如果有好的方案和棘手的問題都會和小夥伴分享。接下來資料庫優化系列即將開啟,主要針對mysql。