緩存穿透、緩存擊穿、緩存雪崩詳解

一、緩存處理流程

前臺請求,後臺先從緩存中取數據,取到直接返回結果,取不到時從數據庫中取,數據庫取到更新緩存,並返回結果,數據庫也沒取到,那直接返回空結果。

在這裏插入圖片描述

二、緩存穿透

描述:

緩存穿透是指緩存和數據庫中都沒有的數據,而用戶不斷髮起請求,如發起爲id爲“-1”的數據或id爲特別大不存在的數據。這時的用戶很可能是攻擊者,攻擊會導致數據庫壓力過大。

解決方案:

接口層增加校驗,如用戶鑑權校驗,id做基礎校驗,id<=0的直接攔截;
從緩存取不到的數據,在數據庫中也沒有取到,這時也可以將key-value對寫爲key-null,緩存有效時間可以設置短點,如30秒(設置太長會導致正常情況也沒法使用)。這樣可以防止攻擊用戶反覆用同一個id暴力攻擊

三、緩存擊穿

描述:

緩存擊穿是指緩存中沒有但數據庫中有的數據(一般是緩存時間到期),這時由於併發用戶特別多,同時讀緩存沒讀到數據,又同時去數據庫去取數據,引起數據庫壓力瞬間增大,造成過大壓力

解決方案:

設置熱點數據永遠不過期。
加互斥鎖,互斥鎖參考代碼如下:

public static String getData(String key) throws InterruptedException{
    //從緩存讀取數據
    String result = getDataFromRedis(key);
    //緩存中不存在數據
    if(result == null){
        //去獲取鎖,獲取成功,去數據庫取數據
        if(reenLock.tryLock()){
            try {
                //從數據庫獲取數據
                result = getDataFromMysql(key);
                //更新緩存數據
                if(result != null){
                    setDataToCache(key, result);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //釋放鎖
                reenLock.unlock();
            }
        }else{
            //獲取鎖失敗
            Thread.sleep(100);//暫停100ms再重新去獲取數據
            result = getData(key);
        }
    }
    return result;
}

說明:

1) 緩存中有數據,直接走上述代碼13行後就返回結果了

2) 緩存中沒有數據,第1個進入的線程,獲取鎖並從數據庫去取數據,沒釋放鎖之前,
	其他並行進入的線程會等待100ms,再重新去緩存取數據。這樣就防止都去數據庫重複取數據,
	重複往緩存中更新數據情況出現。

3) 當然這是簡化處理,理論上如果能根據key值加鎖就更好了,就是線程A從數據庫取key1的數據並不妨礙
	線程B取key2的數據,上面代碼明顯做不到這點。

四、緩存雪崩

描述:

緩存雪崩是指緩存中數據大批量到過期時間,而查詢數據量巨大,引起數據庫壓力過大甚至down機。和緩存擊穿不同的是, 緩存擊穿指併發查同一條數據,緩存雪崩是不同數據都過期了,很多數據都查不到從而查數據庫。

解決方案:

1、緩存數據的過期時間設置隨機,防止同一時間大量數據過期現象發生。
2、如果緩存數據庫是分佈式部署,將熱點數據均勻分佈在不同搞得緩存數據庫中。
3、設置熱點數據永遠不過期。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章