天天看點

Redis 常見緩存問題

作者:馬士兵教育CTO

Redis 業務問題

緩存問題

緩存雪崩

同一時間段内大量的熱點 key 全部過期或者 Redis 當機,所有的請求都打到資料庫上

Redis 常見緩存問題

解決方法:

  1. 給不同的 key 添加不同的 TTL ;
  2. 利用 Redis 叢集提高系統的可用性;
  3. 當系統故障後,可以啟動服務熔斷機制,暫停業務對外通路,直接傳回錯誤,不讓請求通路資料庫;

緩存穿透

用戶端請求的資料在 Redis 和 資料庫 中都不存在,這樣的緩存永遠不會生效

解決方法:

  1. 限制非法的請求,對請求的參數作檢驗
  2. 緩存空對象或預設值
  3. 使用布隆過濾器快速判斷資料是否存在,避免通過查詢資料庫判斷資料是否存在

布隆過濾器

我們在寫入資料庫時,在布隆過濾器中做一個标記。業務線程确認緩存失效後,去布隆過濾器中查詢該值是否存在,而不用去資料庫中進行查詢;

即使發生了緩存穿透,大量請求隻會查詢 Redis 和布隆過濾器,而不會查詢資料庫,保證了資料庫能正常運作,Redis 自身也是支援布隆過濾器的。

布隆過濾器由三個哈希函數,一個位圖數組組成:

  1. 布隆過濾器先将輸入的值通過三個哈希函數得到相應的哈希值;
  2. 将哈希值對數組的長度取模,進而得到相應的下标;
  3. 将三個下标設定為1;

判斷時,布隆過濾器會讀取輸入的值,并通過三個哈希函數轉化成三個數組下标,然後若三個下标對于值均為1,則該資料存在于布隆過濾器中,若有一個為0,則認為該資料不存在布隆過濾器中;

是以,布隆過濾器說存在資料,但實際上該資料可能不存在,布隆過濾器說不存在該資料,則該資料真的不存在;

Redis 常見緩存問題

緩存擊穿

某一個熱點 key 過期消失了,大量的請求打到資料庫上,資料庫很容易被沖垮;

解決方法:

  1. 使用互斥鎖來更新緩存。當某個線程成功擷取鎖後,進行從資料庫中讀取最新的資料,并把新資料存入緩存中去即可,而沒有擷取到鎖的線程進行等待或者傳回請求失敗的響應即可;
  2. 不給熱點資料添加過期值,該 key 由我們手動删除;
  3. 可以在 value 中添加邏輯過期的字段,一旦超過該時間戳就傳回舊的值,再去資料庫進行更新;

緩存更新問題

緩存更新政策

記憶體淘汰 TTL 逾時 主動更新
說明 當Redis記憶體達到最大值時,我們可以通過 Redis 的記憶體淘汰政策,淘汰部分的 key 給每一個key設定過期時間,到達該過期時間後,該 key 會被自動移除 通過業務的方法,更新資料庫和緩存
一緻性 一般
維護成本 一般

主動更新

更新資料庫和更新緩存的順序問題

  1. 先更新緩存,再更新資料庫
Redis 常見緩存問題

出現了資料的不一緻,緩存中的資料為 b,而資料庫中的資料為 a

  1. 先更新資料庫,再更新緩存
Redis 常見緩存問題

出現了資料的不一緻,資料庫中的值為 b,而緩存中的值為 a

是以,無論是「先更新資料庫,再更新緩存」,還是「先更新緩存,再更新資料庫」,這兩個方案都存在并發問題,當兩個請求并發更新同一條資料的時候,可能會出現緩存和資料庫中的資料不一緻的現象。

更新資料庫和删除緩存的順序問題

這裡我們更新資料時,不在更新緩存,而是删除緩存,當讀取不到緩存時,先從資料庫中讀取,再寫入緩存;這種叫做旁路緩存政策

寫操作:

  • 更新資料庫
  • 删除緩存

讀操作:

  • 如果命中了緩存,直接傳回資料
  • 如果沒有命中緩存,則從資料庫讀取資料,再寫入緩存
  1. 先删除緩存,再更新資料庫
Redis 常見緩存問題

此時也出現了資料的不一緻,緩存中的資料為 a,資料庫中的資料為 b

  1. 先更新資料庫,再删除緩存
Redis 常見緩存問題

此時也出現了資料的不一緻,緩存中的資料為 a,資料庫中的資料為 b

但是這種方式出現的幾率會很低,因為更新緩存 a 這步操作是在Redis中進行的,更新資料庫為 b 的操作是在資料庫中進行的,Redis 中的寫入操作比 資料庫中的寫入操作會快很多,是以我們一般采用 更新資料庫 + 删除緩存 的手段

如果強制儲存緩存為最新值,可以為緩存的 key 設定過期時間,如給 a 設定過期時間,可以作為兜底措施

  1. 延遲雙删,針對 先删除緩存,再更新資料庫的情況
Redis 常見緩存問題

僞代碼

scss複制代碼删除緩存 	delete(x)
更新資料 	update(x)

睡眠     	sleep(N)
再次删除緩存	delete(x)
           

前提是:睡眠的時間要比讀請求的過程要大,保證讀請求寫入的緩存要在再次删除緩存之前,不然再次删除緩存後還會把舊的值寫入緩存

繼續閱讀