Redis緩存常見問題及優化方案


緩存可以加速系統的讀寫速度,同時也可以減輕后端數據庫的負載。將緩存加入系統中后,難免會出現一些問題,下面介紹相關的解決方案。

緩存穿透

緩存穿透是指查詢一個根本不存在的數據,緩存層和存儲層都不會命中,通常出於容錯的考慮,如果從存儲層查不到數據則不寫入緩存層。整個過程分為:

  1. 緩存層不命中。

  2. 存儲層不命中,不將空結果寫回緩存。

  3. 返回空結果。

緩存穿透將導致不存在的數據每次請求都要到存儲層去查詢,會使后端存儲負載加大,由於很多后端存儲不具備高並發性,甚至可能造成后端存儲宕掉。通常可以在程序中分別統計總調用數、緩存層命中數、存儲層命中數,如果發現大量存儲層空命中,可能就是出現了緩存穿透。

造成緩存穿透的基本原因有兩個:

  1. 自身業務代碼或者數據出現問題。

  2. 一些惡意攻擊、爬蟲等造成大量空命中。

優化方案

緩存空對象

當存儲層不命中后,仍然將空對象保留到緩存層中,之后再訪問這個數據將會從緩存中獲取,這樣就保護了后端數據庫。緩存空對象會有兩個問題:

  1. 空值做了緩存,意味着緩存層中存了更多的鍵,需要更多的內存空間(如果是攻擊,問題更嚴重),比較有效的方法是針對這類數據設置一個較短的過期時間,讓其自動剔除。
  2. 緩存層和存儲層的數據會有一段時間窗口的不一致,可能會對業務有一定影響。例如過期時間設置為5分鍾,如果此時緩存層添加了這個數據,那此段時間就會出現緩存層和存儲層數據的不一致,此時可以利用消息系統或者其他方式清除掉緩存層中的空對象。

布隆過濾器攔截

簡介

布隆過濾器(Bloom Filter)是由位數組和一組隨機映射函數(哈希函數)兩部分組成的數據結構。相比於平時常用的的List、Map 、Set 等數據結構,它占用空間更少並且效率更高,但是缺點是其返回的結果是概率性的,而不是非常准確的。理論情況下添加到集合中的元素越多,誤報的可能性就越大。並且,存放在布隆過濾器的數據不容易刪除

當一個元素加入布隆過濾器中的時候,會進行如下操作:

  1. 使用布隆過濾器中的哈希函數對元素值進行計算,得到哈希值(有幾個哈希函數得到幾個哈希值)。

  2. 根據得到的哈希值,在位數組中把對應下標的值置為1。

當需要判斷一個元素是否存在於布隆過濾器的時候,會進行如下操作:

  1. 對給定元素再次進行相同的哈希計算。

  2. 得到值之后判斷位數組中的每個元素是否都為1,如果值都為1,那么說明這個值在布隆過濾器中;如果存在一個值不為1,說明該元素不在布隆過濾器中。

不同的字符串可能哈希出來的位置相同,這種情況可以適當增加位數組大小或者調整哈希函數。

總結:布隆過濾器說某個元素存在,小概率會誤判。布隆過濾器說某個元素不在,那么這個元素一定不在。

具體方案

在訪問緩存層和存儲層之前,將存在的key用布隆過濾器提前保存起來,做第一層攔截

例如:一個推薦系統有4億個用戶id,每個小時算法工程師會根據每個用戶之前歷史行為計算出推薦數據放到存儲層中,但是最新的用戶由於沒有歷史行為,就會發生緩存穿透,為此可以將所有推薦數據的用戶做成布隆過濾器。如果布隆過濾器認為該用戶id不存在,那么就不會訪問存儲層,在一定程度保護了存儲層。

方案對比

解決方案 使用場景 維護成本
緩存空對象 數據命中率不高,而且頻繁變化 代碼維護簡單,需要過多的緩存空間,數據不一致
布隆過濾器攔截 數據命中率不高,而且相對固定 代碼維護復雜,緩存空間占用少

緩存雪崩

緩存雪崩是指緩存層由於某些原因不能正常提供服務,於是所有的請求都會來到存儲層,導致存儲層的調用量暴增,造成存儲層也會級聯宕機的情況。

優化方案

  1. 保證緩存層服務高可用性(發生前)。如果緩存層設計成高可用的,即使個別節點、個別機器、甚至是機房宕掉,依然可以提供服務。可以使用Redis Sentinel和Redis Cluster實現高可用。
  2. 依賴隔離組件為后端限流並降級,另外設置一個小緩存(發生中)。降級機制在高並發系統中是非常普遍的,可以使用Java依賴隔離工具Hystrix來實現限流和降級。同時可以在系統內部設置一個小型的本地緩存,可以用ehcache來實現這個功能。
  3. 恢復緩存數據(發生后)。可以使用Redis的持久化機制,利用保存的數據來恢復緩存。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM