什麼是redis的快取雪崩, 穿透, 擊穿?

目前的互聯網系統沒有幾個不使用快取的, 但是只要使用快取的話就會面臨這幾個問題, 如使用redis快取技術, 可能會遇到快取的雪崩, 穿透, 以及擊穿.

 

首先來看一個簡單的正常快取流程:

如用戶訪問JD, 然後JD去訪問redis, 如果redis有這個數據的話,就返回回去, 顯示出來,如果redis沒有數據的話,他就會去請求這個資料庫, 假如資料庫查到這個數據之後, 資料庫就會把這個結果同步到redis裡面去, 同時它會把這個查詢到的結果返回回去.

 

基於上面的流程,我們來看一下什麼是redis的快取雪崩, 穿透, 擊穿?

聲明: 以下例子純屬虛構, 為便於理解所編.

1.redis的快取雪崩

舉個例子, 在JD618的時候, 點進去進入到它的首頁, 這個首頁在618的時候訪問量是非常大的, 所以很多的數據是放到redis裡面去快取起來, 對應redis的100key, 然後後台人員設置的key的失效時間是三個小時, 當這個618期間, 購物車超過三小時之後, 這個首頁的redis快取在一瞬間全部失效, 導致所有的請求都打到了這個資料庫上, 造成資料庫的響應不及時掛掉, 這個時候, 首頁就沒辦法再繼續對外提供服務. 這種現象就是快取雪崩.

解決方案:

a.設置這個快取的失效時間, 讓它不要在同一時間失效, 在我們設置這個快取的時候, 隨機初始化這個失效時間, 這樣的話所有的快取就不會在同一時間失效, 把所有的請求都打到資料庫上.

b.這個redis一般都是集群部署, 我們把這些熱點的key放到不同的節點上去, 讓這些熱點的快取, 平均的分布在這個不同的redis節點上.

c.還有最暴力的方法就是不設置這個快取失效的時間, 讓它永遠不失效.

d.還有就是去跑這個定時任務,  讓它去定時的刷這個快取, 比如說我這個快取設置了三小時時效, 那麼我在失效之前, 就把這個redis快取給他重新跑進去, 然後再設置三小時, 不斷的用這個定時任務去刷新這個快取, 這個快取就不會失效啊.

2.redis的快取穿透

舉個例子, 比如某個網站非常的火爆, 動了某些人的蛋糕,  然後遭到瘋狂的攻擊, 他的攻擊手段就是採用這個快取穿透,  大家都知道資料庫主鍵從0開始遞增, 沒有負數, 那麼這個黑客就利用這一點, 他不斷的利用這個id小於零的這個參數給我發請求, 我把資料庫裡面,所有的數據都放到了redis快取中去,但是他用id小於零的數來請求, redis裡面並沒有這個id小於零的數據, 這樣的話redis就查不到這個結果, 一旦這個redis 查不到這個結果, 就會去資料庫中去查, 造成這個請求不斷的打到這個資料庫上, 因為中間redis這層不能攔截這樣的數據, 這個redis直接被這種數據給穿透了直接穿透到資料庫裡面. 這種現象就是快取穿透. redis和資料庫中都沒有這樣的數據, 一般出現這種情況, 都是一些不正常的用戶.

解決方案:

a.如果這個請求穿透了這個redis, 直接到這個資料庫中, 我資料庫無論查出什麼結果, 是空的還是有值, 都會快取到redis里去, 這樣他下次用同一個參數來發請求的時候, 就不會穿透這個redis.

b.但是他可能換不同的參數, 這個解決方式就是把他這個ip拉黑.

c.但是他也可能換不同的ip, 然後第三個, 就是對參數的合法性校驗, 在判斷這個參數不合法的時候, 直接return掉.

d.第四個方法就是使用布隆過濾器, 這是一個非常好的方式.

3.redis的快取擊穿

舉個列子, 東哥在618的時候想搞一個噱頭, 把他自己珍藏多年的酒拿出來拍賣, 然後有非常多的人對這個酒非常的感興趣, 在9點的時候準時拍賣這個鞋, 然後某個程式設計師就把酒的數據放到了redis快取里, 對應redis一個快取的key, 拍賣的時候呢大家都非常的熱情, 一直拍賣了四小時還沒有結束這個拍賣,  但是這個酒對應的快取key, 他的失效時間是四個半小時, 當大家拍賣到四個半小時的時候, 這個酒的快取key突然失效了, 導致大量的拍賣請求在redis裡面查詢不到這個數據,  這些請求就會直接打到這個資料庫,上面去, 造成這個資料庫響應不及時,掛掉. 這個案例呢就是redis的快取擊穿.

注意:快取擊穿是某一個熱點的key.

解決方式:

a.首先想到的是讓這個快取永遠不過期, 那這個方式肯定不太好.

b.使用分散式鎖, 如果是單體應用的話, 就可以使用這個互斥鎖.

原理: 首先大量的用戶去訪問這個redis的請求數據, 如果有的話就會返回給用戶,  如果redis裡面這個數據為空的話,就會請求這個資料庫請求數據, 我們就在這個請求資料庫這一步, 給他上上鎖, 那麼這個時候就只有一個執行緒, 能搶到這個鎖, 所以也就只有一個執行緒能操作這個資料庫, 那麼這個時候對資料庫的壓力就非常小, 當他查詢到這個數據之後呢, 再把這個快取重新寫到這個redis裡面去, 其他沒有搶到鎖的執行緒, 讓它先睡幾毫秒, 然後再重新去redis裡面去查詢這個數據,因為我們有一個執行緒搶到了這個鎖, 把這個資料庫裡面查詢出來的數據放到了redis裡面去, 那麼其他執行緒在訪問redis的時候, 這個redis裡面就有數據了, 他就不用再去資料庫裡面查詢數據, 他們也就不用再去競爭這個分散式鎖, 他們直接在redis這一步就返回了. 所以這個是解決快取擊穿最好的一個辦法.​​

覺得此文不錯的,點贊轉發,本人非常感謝!

Tags: