緩存擊穿和緩存穿透


緩存擊穿和緩存穿透

1、緩存穿透

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

解決方案:

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

2、緩存擊穿

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

解決方案:

  1. 設置熱點數據永遠不過期
  2. 加鎖
public User findUserById(Integer id) {
    User user = null;
    String key = CACHE_KEY_USER + id;

    // 1、先從 redis 中查詢,如果有結果,直接返回,如果沒有,再去查詢 mysql
    user = (User) redisTemplate.opsForValue().get(key);

    if (user == null) {
        // 2、進來就先加鎖,保證一個請求,讓外面的 redis 等待一下,避免擊穿mysql
        synchronized (UserServiceImpl.class) {
            user = (User) redisTemplate.opsForValue().get(key);
            // 3、 再次查詢redis 還是 null, 就可以去查詢 mysql 了(mysql默認有數據)
            if (user == null) {
                // 5、redis 里面沒有,查詢Mysql
                user = userMapper.selectByPrimaryKey(id);
                if (user == null) {
                    // 6.1、redis + mysql 都沒有數據
                    return user;
                } else {
                    // 6.2 、mysql中有數據 ,需要將數據寫回redis,保證下一次的緩存命中率
                    redisTemplate.opsForValue().setIfAbsent(key, user, 7, TimeUnit.DAYS);
                }
            }
        }
    }
    return user;
}


免責聲明!

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



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