Redis - 緩存穿透以及緩存雪崩

Redis - 緩存穿透以及緩存雪崩

1.緩存收益以及代價

 當我們使用一項技術時,我們就需要對它有一定的瞭解,知道我們爲什麼要去使用它,能夠分析使用這項技術所帶來的的回報以及我們所需要付出的代價。
 緩存所帶來的收益:

  1. 高速讀寫:緩存會加速讀寫速度,利用CPU L1/L2/L3 Cache、Linux page Cache加速硬盤讀寫、瀏覽器緩存、Ehcache緩存緩存數據,其性能都會比關係型數據庫高很多,內存級別的讀寫性能大大優於磁盤級別的讀寫性能。
  2. 降低後端負載:後端服務器業務通過使用Redis減少對MySQL的請求訪問,降低了MySQL負載等。

 緩存所帶來的代價:

  1. 數據不一致:緩存層和數據庫層面數據不一致,例如Redis已經對某條複雜的數據進行緩存,此時通過後臺修改該數據,由於大部分情況下我們不會主動對Redis進行數據刪除,因爲從性能以及包容性來說都不需要進行刪除操作,所以就導致緩存數據同步不及時,這些都和我們自身應用更新策略有關,需要根據實際情況合理設置數據緩存過期時間等相關操作。
  2. 代碼維護成本(人工成本):不適用Redis緩存的情況下,我們只需讀寫MySQL就能實現功能,但當我們加入緩存之後就需要去維護緩存數據的處理邏輯,增加了代碼複雜度。某些情況下會降低項目開發以及測試效率,例如測試人員需要測試有緩存時的情況,也要測試沒有緩存時的情況,另外當測試人員測試功能無需關注緩存時需手動清除對應緩存,否則需要等待數據緩存過期,延長測試時間。
  3. 性能風險:堆內緩存由於是存儲在本地服務器中,由JVM或者本地服務器來維護數據,可能帶來內存溢出的風險甚至影響用戶進程,如ehCacheloadingCache

 堆內緩存和遠程服務器緩存如何選擇?對於這個問題主要考慮以下幾點:

  1. 堆內緩存一般性能更好,遠程緩存需要套接字傳輸。
  2. 用戶級別緩存儘量採用遠程緩存(例如集羣架構下,多臺機器會重複緩存同一組數據)。
  3. 大數據量儘量採用遠程緩存,避免造成應用服務器壓力過大,遵循服務節點化原則。

2.緩存穿透

 在我們使用Redis的過程中,Redis的確幫助我們解決了很多的問題,但是當技術和業務結合在一起時就會發現一些讓人深思的問題。緩存穿透就是其中一個。

2.1 什麼是緩存穿透?

在這裏插入圖片描述

 上面這張圖是我們正常業務場景下的一個流程(客戶端->服務端[Redis->DB]),那麼緩存穿透指的是當用戶查詢數據,再緩存中不存在,並且在數據庫也不存在時,導致用戶查詢這樣的數據(或者惡意攻擊) 在緩存中找不到對應key的value,每次都需要要在數據庫中查詢一遍,然後返回空值。其實這就相當於進行了兩次無用的查詢,這樣請求就繞過緩存直接查數據庫,對數據庫造成了很大的壓力。

2.2 如何防止緩存穿透?

 說到如何防止緩存穿透,這裏我主要提出兩點建議:

  1. 緩存空值:如果DB查詢返回數據或者業務結果爲空,此時我們仍然將空結果進行緩存,設置較短的過期時間(不超過五分鐘)。
  2. 採用布隆過濾器BloomFilter:事先將所有可能存在的數據哈希後放入到一個足夠大的BitMap中,若一個數據一定不存在則會被攔截掉,從而避免了對底層存儲系統的查詢壓力。關於布隆過濾器後面會寫一篇博客對其進行詳細介紹。
    在這裏插入圖片描述

3.緩存雪崩

3.1 什麼是緩存雪崩?

 如果緩存集中在一段時間內失效,發生大量的緩存穿透,所有查詢都落在數據庫上,就會造成了緩存雪崩。 由於原有緩存失效,新緩存未到期間所有原本應該訪問緩存的請求都需要去查詢數據庫,從而對數據庫服務CPU和內存造成巨大壓力,嚴重可能會造成數據庫服務宕機。

3.2 如何防止緩存雪崩?

 這裏我們看看如何防止緩存雪崩:

  1. 加鎖排隊:維護一個mutex互斥鎖,通過RedisSETNX命令去設置一把當前業務操作的鎖(例如setnx lock_uid_001 value nullValue、setnx lock_white_list value nullValue),當操作成功時,再進行LoadDB操作回設緩存,否則重試get緩存。
  2. 數據預熱:緩存預熱就是當我們新部署一個項目系統時,將相關緩存數據直接加載到緩存中。這樣可以避免在用戶請求時候,再去查詢數據庫放入緩存。用戶可以直接查詢事先被預熱的緩存數據,可以預熱大併發量、熱度高的Key緩存數據。
  3. 雙層緩存策略:同一條數據我們可以維護兩套緩存,C1爲原始緩存,C2爲拷貝緩存,當C1失效時,可以讀取C2,都不存在時再去訪問數據庫回設,當然C1緩存失效時間需要設置爲短期,而C2設置爲長期。這種方式最大缺點就是佔用的內存翻倍。
  4. 定時更新緩存策略:對於失效性要求低的緩存,可以在容器啓動初始化時加載放入緩存,採用定時任務更新或移除緩存。
  5. 時間浮動策略:設置不同過期時間,讓緩存失效的時間點儘量均勻,避免集中失效。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章