Redis緩存雪崩、緩存穿透、緩存預熱、緩存更新、緩存降級等問題

今天給大家整理一篇關於Redis經常被問到的問題:緩存雪崩、緩存穿透、緩存預熱、緩存更新、緩存降級等概念的入門及簡單解決方案。
一、緩存雪崩

緩存雪崩我們可以簡單的理解爲:由於原有緩存失效,新緩存未到期間(例如:我們設置緩存時採用了相同的過期時間,在同一時刻出現大面積的緩存過期),所有原本應該訪問緩存的請求都去查詢數據庫了,而對數據庫CPU和內存造成巨大壓力,嚴重的會造成數據庫宕機。從而形成一系列連鎖反應,造成整個系統崩潰。

緩存正常從Redis中獲取,示意圖如下:
在這裏插入圖片描述
緩存失效瞬間示意圖如下:
在這裏插入圖片描述
緩存失效時的雪崩效應對底層系統的衝擊非常可怕!大多數系統設計者考慮用加鎖或者隊列的方式保證來保證不會有大量的線程對數據庫一次性進行讀寫,從而避免失效時大量的併發請求落到底層存儲系統上。還有一個簡單方案就時講緩存失效時間分散開,比如我們可以在原有的失效時間基礎上增加一個隨機值,比如1-5分鐘隨機,這樣每一個緩存的過期時間的重複率就會降低,就很難引發集體失效的事件。

以下簡單介紹兩種實現方式的僞代碼:

(1)碰到這種情況,一般併發量不是特別多的時候,使用最多的解決方案是加鎖排隊,僞代碼如下:

在這裏插入圖片描述

轉存失敗
重新上傳
取消
加鎖排隊只是爲了減輕數據庫的壓力,並沒有提高系統吞吐量。假設在高併發下,緩存重建期間key是鎖着的,這是過來1000個請求999個都在阻塞的。同樣會導致用戶等待超時,這是個治標不治本的方法!

注意:加鎖排隊的解決方式分佈式環境的併發問題,有可能還要解決分佈式鎖的問題;線程還會被阻塞,用戶體驗很差!因此,在真正的高併發場景下很少使用!

(2)還有一個解決辦法解決方案是:給每一個緩存數據增加相應的緩存標記,記錄緩存的是否失效,如果緩存標記失效,則更新數據緩存,實例僞代碼如下:

在這裏插入圖片描述

轉存失敗
重新上傳
取消
解釋說明:

1、緩存標記:記錄緩存數據是否過期,如果過期會觸發通知另外的線程在後臺去更新實際key的緩存;

2、緩存數據:它的過期時間比緩存標記的時間延長1倍,例:標記緩存時間30分鐘,數據緩存設置爲60分鐘。 這樣,當緩存標記key過期後,實際緩存還能把舊數據返回給調用端,直到另外的線程在後臺更新完成後,纔會返回新緩存。

關於緩存崩潰的解決方法,這裏提出了三種方案:使用鎖或隊列、設置過期標誌更新緩存、爲key設置不同的緩存失效時間,還有一各被稱爲“二級緩存”的解決方法,有興趣的讀者可以自行研究。

二、緩存穿透

緩存穿透是指用戶查詢數據,在數據庫沒有,自然在緩存中也不會有。這樣就導致用戶查詢的時候,在緩存中找不到,每次都要去數據庫再查詢一遍,然後返回空(相當於進行了兩次無用的查詢)。這樣請求就繞過緩存直接查數據庫,這也是經常提的緩存命中率問題。

有很多種方法可以有效地解決緩存穿透問題,最常見的則是採用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。

另外也有一個更爲簡單粗暴的方法,如果一個查詢返回的數據爲空(不管是數據不存在,還是系統故障),我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過五分鐘。通過這個直接設置的默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫,這種辦法最簡單粗暴!
在這裏插入圖片描述
轉存失敗
重新上傳
取消
把空結果,也給緩存起來,這樣下次同樣的請求就可以直接返回空了,即可以避免當查詢的值爲空時引起的緩存穿透。同時也可以單獨設置個緩存區域存儲空值,對要查詢的key進行預先校驗,然後再放行給後面的正常緩存處理邏輯。

三、緩存預熱

緩存預熱這個應該是一個比較常見的概念,相信很多小夥伴都應該可以很容易的理解,緩存預熱就是系統上線後,將相關的緩存數據直接加載到緩存系統。這樣就可以避免在用戶請求的時候,先查詢數據庫,然後再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數據!

解決思路:

1、直接寫個緩存刷新頁面,上線時手工操作下;

2、數據量不大,可以在項目啓動的時候自動進行加載;

3、定時刷新緩存;

四、緩存更新

除了緩存服務器自帶的緩存失效策略之外(Redis默認的有6中策略可供選擇),我們還可以根據具體的業務需求進行自定義的緩存淘汰,常見的策略有兩種:

(1)定時去清理過期的緩存;

(2)當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統得到新數據並更新緩存。

兩者各有優劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較複雜!具體用哪種方案,大家可以根據自己的應用場景來權衡。

五、緩存降級

當訪問量劇增、服務出現問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然需要保證服務還是可用的,即使是有損服務。系統可以根據一些關鍵數據進行自動降級,也可以配置開關實現人工降級。

降級的最終目的是保證核心服務可用,即使是有損的。而且有些服務是無法降級的(如加入購物車、結算)。

在進行降級之前要對系統進行梳理,看看系統是不是可以丟卒保帥;從而梳理出哪些必須誓死保護,哪些可降級;比如可以參考日誌級別設置預案:

(1)一般:比如有些服務偶爾因爲網絡抖動或者服務正在上線而超時,可以自動降級;

(2)警告:有些服務在一段時間內成功率有波動(如在95~100%之間),可以自動降級或人工降級,併發送告警;

(3)錯誤:比如可用率低於90%,或者數據庫連接池被打爆了,或者訪問量突然猛增到系統能承受的最大閥值,此時可以根據情況自動降級或者人工降級;

(4)嚴重錯誤:比如因爲特殊原因數據錯誤了,此時需要緊急人工降級。

六、總結

這些都是實際項目中,可能碰到的一些問題,也是面試的時候經常會被問到的知識點,實際上還有很多很多各種各樣的問題,文中的解決方案,也不可能滿足所有的場景,相對來說只是對該問題的入門解決方法。一般正式的業務場景往往要複雜的多,應用場景不同,方法和解決方案也不同,由於上述方案,考慮的問題並不是很全面,因此並不適用於正式的項目開發,但是可以作爲概念理解入門,具體解決方案要根據實際情況來確定!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章