Redis緩存穿透和雪崩(面試高頻,工作常用!)
Redis緩存的使用,極大的提升了應用程序的性能和效率,特別是數據查詢方面。但同時,它也帶來了一 些問題。其中,最要害的問題,就是數據的一致性問題,從嚴格意義上講,這個問題無解。如果對數據 的一致性要求很高,那么就不能使用緩存。 另外的一些典型問題就是,緩存穿透、緩存雪崩和緩存擊穿。目前,業界也都有比較流行的解決方案。
緩存穿透(查不到)
概念
概念
緩存穿透的概念很簡單,用戶想要查詢一個數據,發現redis內存數據庫沒有,也就是緩存沒有命中,於 是向持久層數據庫查詢。發現也沒有,於是本次查詢失敗。當用戶很多的時候,緩存都沒有命中,於是 都去請求了持久層數據庫。這會給持久層數據庫造成很大的壓力,這時候就相當於出現了緩存穿透。
解決方案
解決方案
布隆過濾器
布隆過濾器是一種數據結構,對所有可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則 丟棄,從而避免了對底層存儲系統的查詢壓力;
緩存空對象
當緩存層不命中后,即使返回的空對象也將其緩存起來,同時會設置一個過期時間,之后再訪問這個數據將會從緩存中獲取,保護了后端數據源;
但是這種方法會存在兩個問題:
1、如果空值能夠被緩存起來,這就意味着緩存需要更多的空間存儲更多的鍵,因為這當中可能會有很多 的空值的鍵;
2、即使對空值設置了過期時間,還是會存在緩存層和存儲層的數據會有一段時間窗口的不一致,這對於 需要保持一致性的業務會有影響。
緩存擊穿(量太大,緩存過期)
概述
就比如說:微博又有明星出軌了,大量用戶請求去請求同一個東西,這個時候緩存某個key設置的過期時間是60s,60.1s緩存恢復了,在這0.1s的時間內,大量的請求就跑到了MySQL關系型數據庫里面了,容易使數據庫宕機,這就是擊穿!
這里需要注意和緩存穿透的區別,緩存擊穿,是指一個key非常熱點,在不停的扛着大並發,大並發集中 對這一個點進行訪問,當這個key在失效的瞬間,持續的大並發就穿破緩存,直接請求數據庫,就像在一 個屏障上鑿開了一個洞。
當某個key在過期的瞬間,有大量的請求並發訪問,這類數據一般是熱點數據,由於緩存過期,會同時訪 問數據庫來查詢最新數據,並且回寫緩存,會導使數據庫瞬間壓力過大。
解決方案
設置熱點數據永不過期
從緩存層面來看,沒有設置過期時間,所以不會出現熱點 key 過期后產生的問題。
加互斥鎖
分布式鎖:使用分布式鎖,保證對於每個key同時只有一個線程去查詢后端服務,其他線程沒有獲得分布式鎖的權限,因此只需要等待即可。這種方式將高並發的壓力轉移到了分布式鎖,因此對分布式鎖的考驗很大!
如下圖:當大量請求在key過期后的很短時間內跑到了MySQL數據庫,我們采用分布式鎖,保證只有一個線程跑到MySQL數據庫!對分布式鎖考驗很大!
緩存雪崩
緩存穿透、緩存擊穿、緩存雪崩都是服務器高可用問題!
概念
概念
緩存雪崩,是指在某一個時間段,緩存集中過期失效。(比如說停電了,Redis宕機!)
產生雪崩的原因之一,比如在寫本文的時候,馬上就要到雙十二零點,很快就會迎來一波搶購,這波商品時間比較集中的放入了緩存,假設緩存一個小時。那么到了凌晨一點鍾的時候,這批商品的緩存就都過期了。而對這批商品的訪問查詢,都落到了數據庫上,對於數據庫而言,就會產生周期性的壓力波峰。於是所有的請求都會達到存儲層,存儲層的調用量會暴增,造成存儲層也會掛掉的情況。
其實集中過期,倒不是非常致命,比較致命的緩存雪崩,是緩存服務器某個節點宕機或斷網。因為自然 形成的緩存雪崩,一定是在某個時間段集中創建緩存,這個時候,數據庫也是可以頂住壓力的。無非就 是對數據庫產生周期性的壓力而已。而緩存服務節點的宕機,對數據庫服務器造成的壓力是不可預知 的,很有可能瞬間就把數據庫壓垮。
雙十一:停掉一些服務,保證主要的服務可用!這就是雙十一當前退款是不可能退款的原因!
解決方案
redis高可用
這個思想的含義是,既然redis有可能掛掉,那我多增設幾台redis,這樣一台掛掉之后其他的還可以繼續 工作,其實就是搭建的集群。(異地多活!)
限流降級
這個解決方案的思想是,在緩存失效后,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對 某個key只允許一個線程查詢數據和寫緩存,其他線程等待。
數據預熱
數據加熱的含義就是在正式部署之前,我先把可能的數據先預先訪問一遍,這樣部分可能大量訪問的數 據就會加載到緩存中。在即將發生大並發訪問前手動觸發加載緩存不同的key,設置不同的過期時間,讓緩存失效的時間點盡量均勻。