緩存擊穿/穿透/雪崩
Intro
使用緩存需要了解幾個緩存問題,緩存擊穿、緩存穿透以及緩存雪崩,需要了解它們產生的原因以及怎么避免,尤其是當你打算設計自己的緩存框架的時候需要考慮如何處理這些問題。
緩存擊穿
一般的緩存系統,都是按照 key 去緩存查詢,如果不存在對應的 value ,就應該去后端系統查找(比如數據庫)。如果 key 對應的 value 是一定不存在的,並且對該 key 並發請求量很大,就會對后端系統就會造成很大的壓力。
在高並發下,多線程同時查詢同一個資源,如果緩存中沒有這個資源,那么這些線程都會去后端服務或數據庫查找,對數據庫造成極大壓力,緩存也就失去存在的意義。
緩存擊穿解決方案
導致緩存擊穿的問題在於高並發多線程情景下,許多請求一下子都到后端服務和數據庫,導致后端服務與數據庫的壓力驟增。
處理這個問題,在多線程請求同一個 key 的時候,進行排隊,這樣第一次請求后端服務和數據庫之后更新緩存的值,下一個請求從緩存中取數據的時候就會拿到緩存數據,不會再請求后端服務和數據庫。
緩存穿透
緩存穿透是指用戶查詢數據,在數據庫沒有,自然在緩存中也不會有。這樣就導致用戶查詢的時候,在緩存中找不到,每次都要去數據庫中查詢,從而失去了緩存的意義而且相比直接查詢數據庫還增加了每次都去查緩存。
緩存穿透解決方案
導致問題出現的原因在於請求一個不存在的數據從而使得緩存始終不存在進而導致后端系統(主要是數據庫)要承受很大的壓力,所以想要解決這個問題,就勢必就在緩存這里攔截住大量的請求,使得最終走到后端系統,查詢數據庫的請求盡可能的少。
一般處理這個問題,緩存不存在的時候會在緩存中設置一個時間較短的內容為空的緩存,從而減少實際請求到后端和進行數據庫查詢的次數。
復雜一些的解決方案有 布隆過濾器,基本原理是設置一個 list,查詢緩存的時候從 list 里進行判斷,這里不做多介紹。
布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實際上是一個很長的二進制向量和一系列隨機映射函數。布隆過濾器可以用於檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困難
如果想要判斷一個元素是不是在一個集合里,一般想到的是將所有元素保存起來,然后通過比較確定。鏈表,樹等等數據結構都是這種思路. 但是隨着集合中元素的增加,我們需要的存儲空間越來越大,檢索速度也越來越慢(O(n),O(logn))。不過世界上還有一種叫作散列表(又叫哈希表,Hash table)的數據結構。它可以通過一個Hash函數將一個元素映射成一個位陣列(Bit array)中的一個點。這樣一來,我們只要看看這個點是不是1就可以知道集合中有沒有它了。這就是布隆過濾器的基本思想。
緩存雪崩
當緩存服務器重啟或者大量緩存集中在某一個時間失效,這樣在失效的時候,也會給后端系統和數據庫帶來很大壓力.
緩存雪崩解決方案
導致出現緩存雪崩的根本原因在於緩存大量失效,從而導致大量請求沒有命中緩存,大量請求走到后端服務和數據庫,造成壓力。
如果系統啟動就依賴很多緩存,那可以通過其它服務進行緩存預熱,提前把需要的數據放到緩存中,避免系統啟動大量請求直接請求到后端服務和數據庫。
既然是由於同一時間緩存大量失效,我們也可以着手從緩存的失效時間上,做一些優化,讓緩存不要在同一時間點失效。
具體的實施辦法,你可以在設置失效時間的時候隨機加幾秒過期時間,避免同一時間點緩存大量失效。
Reference
- https://github.com/WeihanLi/WeihanLi.Redis/issues/2
- https://www.cnblogs.com/jinjiangongzuoshi/archive/2016/03/03/5240280.html
- https://blog.csdn.net/zeb_perfect/article/details/54135506
- https://blog.csdn.net/bushanyantanzhe/article/details/79459095
- https://baike.baidu.com/item/布隆過濾器/5384697?fr=aladdin
Contact
Contact me: weihanli@outlook.com