緩存失效了,怎么辦?
Part 01
前言
在高并發的系統架構中,大量網絡請求的并發處理,導致數據庫的I/O消耗是非常巨大的,為了快速讀取數據,減少網絡請求時延,緩解數據庫的壓力,因此在軟件開發中引入了緩存技術。但是在緩存的使用過程中也會遇到一些特殊情況導致緩存失效,常見的緩存失效的情況有三種:緩存穿透、緩存擊穿、緩存雪崩。
Part 02
緩存失效的三種情況
緩存(以Redis緩存為例)的引入可以減少請求數據庫的次數,提高查詢效率,從而提升系統性能。一般的流程是:應用發起請求后,先查詢緩存中是否存在所需數據,如果緩存中存在,直接返回數據,如果緩存中不存在所需數據,則需要去查詢數據庫,如果數據庫中存在所需數據,則一方面存入緩存,另一方面返回查詢結果,如果數據庫中不存在,則返回空或者錯誤。
圖1 緩存使用流程圖
- 緩存穿透
緩存穿透(Cache Penetration)是指查詢一個一定不存在的數據,即用戶訪問的數據既不在緩存當中,也不在數據庫中。由于緩存中查詢不到數據,請求會去查詢數據庫,然而數據庫中也不存在該數據,也不會寫入緩存,導致查詢該數據的時候,每次都要去數據庫中查詢,給數據庫到來壓力。
- 緩存雪崩
緩存雪崩(Cache Avalanche)是指大量的緩存數據在某一時刻超過了緩存的過期時間,同時失效,導致高并發的請求同時去訪問數據庫,造成數據庫壓力過大,導致系統崩潰。這是針對多個緩存數據而言的。
- 緩存擊穿
緩存擊穿(Cache Breakdown)是指緩存過期的一瞬間,有大量的請求去查詢同一個緩存數據,由于該數據在承載著大并發,當該數據失效的一瞬間,持續的大并發就會直接去請求數據庫,造成數據庫壓力倍增。這是針對一個緩存數據而言的。
Part 03
解決方案
針對緩存穿透的解決方案:
1.第一種方案是采用布隆過濾器進行數據攔截。這也是針對緩存擊穿采用的常用方案。在寫入數據時,使用布隆過濾器對數據的key進行標記,當帶有數據key的請求過來后,先用布隆過濾器驗證key是否存在,如果存在,再進入緩存或者數據庫中進行查詢。
2.第二種方案是緩存空值。當在數據庫中查詢不到數據時,將其緩存為空值或者默認值。此時需要注意,針對其的緩存過期時間不宜過長,一般設置為5分鐘內,當數據庫被寫入或者更新該key的新數據時,緩存必須同時更新,保證數據的一致性。
針對緩存雪崩的解決方案:
1.一般是將key的過期時間后面增加一個隨機數,讓過期時間分散開,使key均勻失效,減少緩存時間過期的重復率。
2.利用加鎖或隊列的方式,保證緩存單線程寫,但是這種方案會影響并發量,多個請求過來時,只有一個在進行正常的操作,其他請求都會在等待的狀態,影響程序性能,不推薦使用。
3.使用緩存標記,這是比較好的解決辦法。判斷標記是否過期,過期則去數據庫中請求,而緩存數據的過期時間要設置的比緩存標記長些,如此一來,當一個請求去操作數據庫的時候,其他的請求拿到的是上一次的緩存數據。
針對緩存擊穿的解決方案:
1.使用互斥鎖,當緩存的key過期時,多個請求過來時只允許一個請求去查詢數據庫構建緩存,其他請求等待該請求執行完畢之后,重新從緩存中獲取數據。
2.針對訪問量比較大的數據,即熱點數據,不設置緩存過期時間,后臺異步更新緩存,適用于不嚴格要求緩存一致性的場景。