本篇對緩存三劍客問題進行介紹和解決方案說明,下篇將進行實踐,有需要的同學可以跳轉下篇查看實踐篇:(待發布)
緩存三劍客是什么?
????????緩存三劍客指的是在分布式系統下使用緩存技術最常見的三類典型問題。它們分別是:
-
緩存穿透:請求不存在的數據。
-
緩存擊穿:熱點數據突然過期。
-
緩存雪崩:大量數據同時過期。
????????三種問題都會導致緩存失效,對數據庫造成巨大壓力,可能會導致數據庫崩潰,引發系統性崩潰。所以說,學會如何預防和解決這三種問題顯得尤為重要。
緩存穿透問題
問題描述
????????緩存穿透問題指的是:當用戶訪問的數據即不在緩存中,又不在數據庫中,也就是訪問系統中不存在的數據,導致請求在訪問緩存的時候發現不存在緩存,持續的去訪問數據庫。并且在訪問數據庫后,因該數據不存在導致無法構建緩存。若存在大量該請求時,數據庫壓力過大,可能會導致數據庫崩潰。
????????用一句話來說:用戶請求系統中不存在的數據,導致無法構建緩存,持續訪問數據庫,導致系統壓力過大。
可能產生的原因
????????一般情況下,在我們的系統中不應該存在這種可以訪問不存在的數據的方法。大概率是不好的用戶進行惡意請求。比如一個用戶了解到了系統中的一個API的訪問方法,那么用戶可以通過構建出來一個不存在的數據,然后去持續壓力訪問該API,就會導致緩存穿透問題的發生。
解決方案
????????明確一下我們需要解決的問題:我們要解決因為緩存穿透問題導致的數據庫壓力過大。那么換句話來說,我們只需要將這些無效數據盡可能的在訪問數據庫之前屏蔽掉就好了。
方案1:緩存空數據
????????如果我們發現一個API請求的數據在我們的數據庫和緩存中都不存在的話,我們可以通過將這個無效數據也緩存到Redis中,若惡意請求的key值都是一致的話,就會被我們攔截在緩存,防止數據庫壓力過大。
????????該方案也存在一些問題:
-
如果惡意請求的數據是通過一個方式構造出來的,構造出來了大量的無效數據,那我們使用該方法可能會導致Redis中存取了大量的無效數據,這其實對Redis來說也不是很友好的。所以我們需要為這些緩存也要添加一個TTL過期時間,讓Redis將這些數據在一段時間之后進行過期。需要注意的是,這個位置如果我們的過期時間設置不合理的話,也可能會出現我們后文會出現到的問題:緩存雪崩問題。
方案2:布隆過濾器
????????布隆過濾器是一個比較好用的數據結構,通過布隆過濾器,我們可以快速判斷一個數據是否存在我們書庫中。
????????布隆過濾器簡單來說是由兩部分組成的:一個二進制向量(也可以說是個Bit Array二進制數組)和一系列的哈希函數。
????????布隆過濾器通過一個較大的bit數組用于保存所有數據,數字中每個數組只占1bit,并且每個元素的表示只能是0或1用于表示是否存在。當我們添加元素的時候,布隆過濾器通過一系列的哈希函數將數據進行計算,計算后的結果映射到數組中,將對應位置映射為1。當查詢元素的時候,通過哈希函數將元素映射,查看對應位置是否均為1,如果都為1的話則表示元素可能存在我們的數據中。
????????需要注意的是:如果我們查詢數據映射均為1的時候,我們只能說這個元素可能存在。因為存在多個元素映射到同樣的一系列位置的情況(哈希沖突)。所以我們不能一定確定數據存在。但是我們至少可以確定,如果映射的位置存在一位以上的0,那么可以說明這個數據一定不存在。
緩存擊穿問題
問題描述
????????緩存擊穿問題指的是:當我們處于一個高并發的情況下,存在一個熱點數據的訪問量非常大,在我們依然存在大量請求的同時這個熱點數據的緩存突然失效(可能是過期了或者被刪除),導致大量的并發請求同時穿透緩存,直接訪問數據庫,導致數據庫壓力過大,可能會導致系統崩潰。
????????用一句話來說:熱點數據過期,導致大量并發請求穿透緩存,直接訪問數據庫。
可能產生的原因
????????假設我們商城系統對某個商品的有秒殺活動,在秒殺商品活動結束的時候緩存過期,導致大量的后續請求直接訪問到數據庫中。
????????本質上就是熱點數據在高并發期間緩存過期。
解決方案
方案1:加互斥鎖
????????通過在緩存失效后,添加一個互斥鎖,保證只有一個請求去查詢數據庫,然后更新緩存,這樣就可以保證后續的請求可以正確的訪問緩存,不會直接訪問數據庫導致數據庫壓力過大。
方案2:提前預熱熱點數據
????????在發布前,我們應該對系統中存在的熱點數據應該有預知的。我們可以針對熱點數據進行提前預熱,將其存入緩存中并設置合適的過期時間。
方案3:設置熱點數據永不過期
????????該方案在選用的時候需要考慮實際情況,如果我們這個熱點數據是一致會被訪問,也就是說這個熱點數據一直都是熱點數據的話,我們可以考慮設置這個熱點數據永不過期。如果,熱點數據是有失效性的,那么這個方案并不很適用。
緩存雪崩問題
問題描述
????????緩存雪崩問題指的是:當我們存在系統中大部分緩存在同一時間失效,那么在緩存重建的過程中,如果存在大量的請求,這些請求會越過緩存直接對數據庫進行訪問,對數據庫造成巨大的壓力,可能會導致系統崩潰。當然,緩存服務器若突然宕機了,也會造成緩存雪崩問題。
可能產生的原因
-
大量Key的TTL結束時間一致:我們設置緩存過期時間的時候可能設置的并不是很合理,導致大量的緩存在同一時間過期了,導致緩存雪崩問題。
-
緩存服務器宕機:緩存服務都沒了,所有請求肯定都會直接對數據庫進行訪問,形成緩存雪崩問題。
解決方案
????????對于可能造成緩存雪崩的兩種原因,有下面不同的解決方案:
方案1:設置隨機失效時間
????????通過為每個需要添加隨機過期時間的Key添加隨機的失效時間偏移量,避免在同一時間內有大量數據過期。
????????該方案可以解決大量Key同一時間過期的情況,但是有效性也比較有限,如果存在大量數據同時添加緩存的話,該方案可能有些治標不治本。
方案2:采用多級緩存架構
????????通過構建多級緩存,不同層級設置不同的過期時間策略,保證同一時間內,存在可用的緩存。
方案3:部署集群
????????通過部署Redis集群,防止因為單個緩存宕機導致服務不可用。
總結
????????本篇對于緩存三劍客問題進行說明,在下篇文章將對各個問題以及對應的解決方案進行實踐。
【Redis】緩存三劍客問題實踐(下):(待發布)