目前的互聯網系統沒有幾個不使用緩存的, 但是只要使用緩存的話就會面臨這幾個問題, 如使用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這一步就返回了. 所以這個是解決緩存擊穿最好的一個辦法.?
覺得此文不錯的,點贊轉發,本人非常感謝!