Redis 緩存擊穿、穿透、雪崩


1.緩存擊穿

什么是緩存擊穿

緩存擊穿和緩存穿透從名詞上可能很難區分開來,它們的區別是:穿透表示底層數據庫沒有數據且緩存內也沒有數據,擊穿表示底層數據庫有數據而緩存內沒有數據。
當熱點數據key從緩存內失效時,大量訪問同時請求這個數據,就會將查詢下沉到數據庫層,此時數據庫層的負載壓力會驟增,我們稱這種現象為"緩存擊穿"。

解決方案:

  1. 延長熱點key的過期時間或者設置永不過期,如排行榜,首頁等一定會有高並發的接口;
  2. 利用互斥鎖保證同一時刻只有一個客戶端可以查詢底層數據庫的這個數據,一旦查到數據就緩存至Redis內,避免其他大量請求同時穿過Redis訪問底層數據庫;
import redis
from time import sleep

conn = redis.Redis('127.0.0.1')


def get(key, key_time, mutex_time):
    value = conn.get(key)
    print(value)
    if value == None:
        key_mutex = key + "_nx"
        # 設置超時,防止del操作失敗的時候,下次緩存過期一直不能load db
        # 待優化  使用lua保證原子性  避免死鎖 也就是說下列代碼有死鎖風險
        if conn.setnx(key_mutex, 1) == 1:
            conn.expire(key_mutex, mutex_time)
            sleep(5)
            value = "我是查詢數據"
            conn.set(key, value, key_time)
            conn.delete(key_mutex)
            return value
        else:
            # 這個時候代表同時候的其他線程已經loaddb並回設到緩存了,這時候重試獲取緩存值即可
            # TODO 這里需要補充超時時間 時間超過某個限制 raise 異常
            sleep(0.1)
            get(key, key_time, mutex_time)  # 重試

    else:
        return value

2.緩存穿透

什么是穿透

當查詢Redis中沒有的數據時,該查詢會下沉到數據庫層,同時數據庫層也沒有該數據,當這種情況大量出現或被惡意攻擊時,接口的訪問全部透過Redis訪問數據庫,而數據庫中也沒有這些數據,我們稱這種現象為"緩存穿透"。
緩存穿透會穿透Redis的保護,提升底層數據庫的負載壓力,同時這類穿透查詢沒有數據返回也造成了網絡和計算資源的浪費。

解決方案

  1. 在接口訪問層對用戶做校驗,如接口傳參、登陸狀態、n秒內訪問接口的次數;
  2. 利用布隆過濾器,將數據庫層有的數據key存儲在位數組中,以判斷訪問的key在底層數據庫中是否存在;
    PS:布隆過濾器有誤判率,雖然不能完全避免數據穿透的現象,但已經可以將99.99%的穿透查詢給屏蔽在Redis層了,極大的降低了底層數據庫的壓力,減少了資源浪費。

3.緩存雪崩

什么是緩存雪崩

緩存雪崩是緩存擊穿的"大面積"版,緩存擊穿是數據庫緩存到Redis內的熱點數據失效導致大量並發查詢穿過redis直接擊打到底層數據庫,而緩存雪崩是指Redis中大量的key幾乎同時過期,
然后大量並發查詢穿過redis擊打到底層數據庫上,此時數據庫層的負載壓力會驟增,我們稱這種現象為"緩存雪崩"。事實上緩存雪崩相比於緩存擊穿更容易發生,對於大多數公司來講,
同時超大並發量訪問同一個過時key的場景的確太少見了,而大量key同時過期,大量用戶訪問這些key的幾率相比緩存擊穿來說明顯更大。

解決方案:

  1. 在可接受的時間范圍內隨機設置key的過期時間,分散key的過期時間,以防止大量的key在同一時刻過期;(PS:給key加日期,使用定時任務將對應數據刷進redis緩存)
  2. 對於一定要在固定時間讓key失效的場景(例如每日12點准時更新所有最新排名),可以在固定的失效時間時在接口服務端設置隨機延時,將請求的時間打散,讓一部分查詢先將數據緩存起來;
  3. 延長熱點key的過期時間或者設置永不過期,這一點和緩存擊穿中的方案一樣;


免責聲明!

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



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