国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Redis緩存穿透、擊穿、雪崩問題及其解決方法

這篇具有很好參考價值的文章主要介紹了Redis緩存穿透、擊穿、雪崩問題及其解決方法。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1 緩存穿透

1.1 概念及其解決思路

緩存穿透 :緩存穿透是指客戶端請求的數(shù)據(jù)在緩存中和數(shù)據(jù)庫中都不存在,這樣緩存永遠不會生效,這些請求都會打到數(shù)據(jù)庫。

常見的解決方案有兩種:

  • 緩存空對象
    • 優(yōu)點:實現(xiàn)簡單,維護方便
    • 缺點:
      • 額外的內(nèi)存消耗
      • 可能造成短期的不一致
  • 布隆過濾
    • 優(yōu)點:內(nèi)存占用較少,沒有多余key
    • 缺點:
      • 實現(xiàn)復雜
      • 存在誤判可能

**緩存空對象思路分析:**當我們客戶端訪問不存在的數(shù)據(jù)時,先請求redis,但是此時redis中沒有數(shù)據(jù),此時會訪問到數(shù)據(jù)庫,但是數(shù)據(jù)庫中也沒有數(shù)據(jù),這個數(shù)據(jù)穿透了緩存,直擊數(shù)據(jù)庫,我們都知道數(shù)據(jù)庫能夠承載的并發(fā)不如redis這么高,如果大量的請求同時過來訪問這種不存在的數(shù)據(jù),這些請求就都會訪問到數(shù)據(jù)庫,簡單的解決方案就是哪怕這個數(shù)據(jù)在數(shù)據(jù)庫中也不存在,我們也把這個數(shù)據(jù)存入到redis中去,這樣,下次用戶過來訪問這個不存在的數(shù)據(jù),那么在redis中也能找到這個數(shù)據(jù)就不會進入到緩存了

**布隆過濾:**布隆過濾器其實采用的是哈希思想來解決這個問題,通過一個龐大的二進制數(shù)組,走哈希思想去判斷當前這個要查詢的這個數(shù)據(jù)是否存在,如果布隆過濾器判斷存在,則放行,這個請求會去訪問redis,哪怕此時redis中的數(shù)據(jù)過期了,但是數(shù)據(jù)庫中一定存在這個數(shù)據(jù),在數(shù)據(jù)庫中查詢出來這個數(shù)據(jù)后,再將其放入到redis中,

假設(shè)布隆過濾器判斷這個數(shù)據(jù)不存在,則直接返回

這種方式優(yōu)點在于節(jié)約內(nèi)存空間,存在誤判,誤判原因在于:布隆過濾器走的是哈希思想,只要哈希思想,就可能存在哈希沖突

Redis緩存穿透、擊穿、雪崩問題及其解決方法

1.2 編碼解決商品查詢的緩存穿透問題:

核心思路如下:

在原來的邏輯中,我們?nèi)绻l(fā)現(xiàn)這個數(shù)據(jù)在mysql中不存在,直接就返回404了,這樣是會存在緩存穿透問題的

現(xiàn)在的邏輯中:如果這個數(shù)據(jù)不存在,我們不會返回404 ,還是會把這個數(shù)據(jù)寫入到Redis中,并且將value設(shè)置為空,歐當再次發(fā)起查詢時,我們?nèi)绻l(fā)現(xiàn)命中之后,判斷這個value是否是null,如果是null,則是之前寫入的數(shù)據(jù),證明是緩存穿透數(shù)據(jù),如果不是,則直接返回數(shù)據(jù)。

Redis緩存穿透、擊穿、雪崩問題及其解決方法

小總結(jié):

緩存穿透產(chǎn)生的原因是什么?

  • 用戶請求的數(shù)據(jù)在緩存中和數(shù)據(jù)庫中都不存在,不斷發(fā)起這樣的請求,給數(shù)據(jù)庫帶來巨大壓力

緩存穿透的解決方案有哪些?

  • 緩存null值
  • 布隆過濾
  • 增強id的復雜度,避免被猜測id規(guī)律
  • 做好數(shù)據(jù)的基礎(chǔ)格式校驗
  • 加強用戶權(quán)限校驗
  • 做好熱點參數(shù)的限流

2 緩存雪崩問題及解決思路

緩存雪崩是指在同一時段大量的緩存key同時失效或者Redis服務宕機,導致大量請求到達數(shù)據(jù)庫,帶來巨大壓力。

解決方案:

  • 給不同的Key的TTL添加隨機值
  • 利用Redis集群提高服務的可用性
  • 給緩存業(yè)務添加降級限流策略
  • 給業(yè)務添加多級緩存

Redis緩存穿透、擊穿、雪崩問題及其解決方法

3 緩存擊穿問題及解決思路

緩存擊穿問題也叫熱點Key問題,就是一個被高并發(fā)訪問并且緩存重建業(yè)務較復雜的key突然失效了,無數(shù)的請求訪問會在瞬間給數(shù)據(jù)庫帶來巨大的沖擊。

常見的解決方案有兩種:

  • 互斥鎖
  • 邏輯過期

邏輯分析:假設(shè)線程1在查詢緩存之后,本來應該去查詢數(shù)據(jù)庫,然后把這個數(shù)據(jù)重新加載到緩存的,此時只要線程1走完這個邏輯,其他線程就都能從緩存中加載這些數(shù)據(jù)了,但是假設(shè)在線程1沒有走完的時候,后續(xù)的線程2,線程3,線程4同時過來訪問當前這個方法, 那么這些線程都不能從緩存中查詢到數(shù)據(jù),那么他們就會同一時刻來訪問查詢緩存,都沒查到,接著同一時間去訪問數(shù)據(jù)庫,同時的去執(zhí)行數(shù)據(jù)庫代碼,對數(shù)據(jù)庫訪問壓力過大

Redis緩存穿透、擊穿、雪崩問題及其解決方法

解決方案一、使用鎖來解決:

因為鎖能實現(xiàn)互斥性。假設(shè)線程過來,只能一個人一個人的來訪問數(shù)據(jù)庫,從而避免對于數(shù)據(jù)庫訪問壓力過大,但這也會影響查詢的性能,因為此時會讓查詢的性能從并行變成了串行,我們可以采用tryLock方法 + double check來解決這樣的問題。

假設(shè)現(xiàn)在線程1過來訪問,他查詢緩存沒有命中,但是此時他獲得到了鎖的資源,那么線程1就會一個人去執(zhí)行邏輯,假設(shè)現(xiàn)在線程2過來,線程2在執(zhí)行過程中,并沒有獲得到鎖,那么線程2就可以進行到休眠,直到線程1把鎖釋放后,線程2獲得到鎖,然后再來執(zhí)行邏輯,此時就能夠從緩存中拿到數(shù)據(jù)了。

Redis緩存穿透、擊穿、雪崩問題及其解決方法

解決方案二、邏輯過期方案

方案分析:我們之所以會出現(xiàn)這個緩存擊穿問題,主要原因是在于我們對key設(shè)置了過期時間,假設(shè)我們不設(shè)置過期時間,其實就不會有緩存擊穿的問題,但是不設(shè)置過期時間,這樣數(shù)據(jù)不就一直占用我們內(nèi)存了嗎,我們可以采用邏輯過期方案。

我們把過期時間設(shè)置在 redis的value中,注意:這個過期時間并不會直接作用于redis,而是我們后續(xù)通過邏輯去處理。假設(shè)線程1去查詢緩存,然后從value中判斷出來當前的數(shù)據(jù)已經(jīng)過期了,此時線程1去獲得互斥鎖,那么其他線程會進行阻塞,獲得了鎖的線程他會開啟一個 線程去進行 以前的重構(gòu)數(shù)據(jù)的邏輯,直到新開的線程完成這個邏輯后,才釋放鎖, 而線程1直接進行返回,假設(shè)現(xiàn)在線程3過來訪問,由于線程線程2持有著鎖,所以線程3無法獲得鎖,線程3也直接返回數(shù)據(jù),只有等到新開的線程2把重建數(shù)據(jù)構(gòu)建完后,其他線程才能走返回正確的數(shù)據(jù)。

這種方案巧妙在于,異步的構(gòu)建緩存,缺點在于在構(gòu)建完緩存之前,返回的都是臟數(shù)據(jù)。

Redis緩存穿透、擊穿、雪崩問題及其解決方法

進行對比

**互斥鎖方案:**由于保證了互斥性,所以數(shù)據(jù)一致,且實現(xiàn)簡單,因為僅僅只需要加一把鎖而已,也沒其他的事情需要操心,所以沒有額外的內(nèi)存消耗,缺點在于有鎖就有死鎖問題的發(fā)生,且只能串行執(zhí)行性能肯定受到影響

邏輯過期方案: 線程讀取過程中不需要等待,性能好,有一個額外的線程持有鎖去進行重構(gòu)數(shù)據(jù),但是在重構(gòu)數(shù)據(jù)完成前,其他的線程只能返回之前的數(shù)據(jù),且實現(xiàn)起來麻煩

Redis緩存穿透、擊穿、雪崩問題及其解決方法

3.1 利用互斥鎖解決緩存擊穿問題

假設(shè)有一個場景,店家列表頁可以進入店家詳情頁,所有的店家詳情頁數(shù)據(jù)會提前緩存到redis;用戶在店鋪列表頁點擊訪問店家詳情頁,此時某一個key失效,緩存查詢不到,并且有大量請求訪問導致數(shù)據(jù)庫壓力增加,此時利用setnx鎖住關(guān)鍵業(yè)務代碼,只允許搶到鎖線程進入執(zhí)行業(yè)務,未搶到鎖的線程則進行重試。

核心思路:相較于原來從緩存中查詢不到數(shù)據(jù)后直接查詢數(shù)據(jù)庫而言,現(xiàn)在的方案是 進行查詢之后,如果從緩存沒有查詢到數(shù)據(jù),則進行互斥鎖的獲取,獲取互斥鎖后,判斷是否獲得到了鎖,如果沒有獲得到,則休眠,過一會再進行嘗試,直到獲取到鎖為止,才能進行查詢

如果獲取到了鎖的線程,再去進行查詢,查詢后將數(shù)據(jù)寫入redis,再釋放鎖,返回數(shù)據(jù),利用互斥鎖就能保證只有一個線程去執(zhí)行操作數(shù)據(jù)庫的邏輯,防止緩存擊穿

Redis緩存穿透、擊穿、雪崩問題及其解決方法

操作鎖的代碼:

核心思路就是利用redis的setnx方法來表示獲取鎖,該方法含義是redis中如果沒有這個key,則插入成功,返回1,在stringRedisTemplate中返回true, 如果有這個key則插入失敗,則返回0,在stringRedisTemplate返回false,我們可以通過true,或者是false,來表示是否有線程成功插入key,成功插入的key的線程我們認為他就是獲得到鎖的線程。

private boolean tryLock(String key) {
    Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
    return BooleanUtil.isTrue(flag);
}

private void unlock(String key) {
    stringRedisTemplate.delete(key);
}

操作代碼:

    public Shop queryWithMutex(Long id)  {
        String key = CACHE_SHOP_KEY + id;
        // 1、從redis中查詢商鋪緩存
        String shopJson = stringRedisTemplate.opsForValue().get("key");
        // 2、判斷是否存在
        if (StrUtil.isNotBlank(shopJson)) {
            // 存在,直接返回
            return JSONUtil.toBean(shopJson, Shop.class);
        }
        //判斷命中的值是否是空值
        if (shopJson != null) {
            // 不為null,說明只能是空字符串(空值),返回一個錯誤信息
            // 這種情況一般是經(jīng)歷了緩存穿透,數(shù)據(jù)庫查詢不到并進行緩存空值
            return null;
        }
        // 4.實現(xiàn)緩存重構(gòu)
        //4.1 獲取互斥鎖
        String lockKey = "lock:shop:" + id;
        Shop shop = null;
        try {
            boolean isLock = tryLock(lockKey);
            // 4.2 判斷否獲取成功
            if(!isLock){
                //4.3 失敗,則休眠重試
                Thread.sleep(50);
                return queryWithMutex(id);
            }
            //4.4 成功,根據(jù)id查詢數(shù)據(jù)庫
            shop = getById(id);
            // 5.不存在,返回錯誤
            if(shop == null){  // 緩存穿透想象,此處利用空值緩存解決
                //將空值寫入redis
                stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);
                //返回錯誤信息
                return null;
            }
            //6.寫入redis,設(shè)置過期時間
            stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_NULL_TTL,TimeUnit.MINUTES);

        }catch (Exception e){
            throw new RuntimeException(e);
        }
        finally {
            //7.釋放互斥鎖
            unlock(lockKey);
        }
        return shop;

3.2 利用邏輯過期解決緩存擊穿問題

需求:修改根據(jù)id查詢商鋪的業(yè)務,基于邏輯過期方式來解決緩存擊穿問題

思路分析:當用戶開始查詢redis時,判斷是否命中,如果沒有命中則直接返回空數(shù)據(jù),不查詢數(shù)據(jù)庫,而一旦命中后,將value取出,判斷value中的過期時間是否滿足,如果沒有過期,則直接返回redis中的數(shù)據(jù),如果過期,則在開啟獨立線程后直接返回之前的數(shù)據(jù),獨立線程去重構(gòu)數(shù)據(jù),重構(gòu)完成后釋放互斥鎖。

Redis緩存穿透、擊穿、雪崩問題及其解決方法

如果封裝數(shù)據(jù):因為現(xiàn)在redis中存儲的數(shù)據(jù)的value需要帶上過期時間,此時要么你去修改原來的實體類,要么你

步驟一、

新建一個實體類,我們采用第二個方案,這個方案,對原來代碼沒有侵入性。

@Data
public class RedisData {
    private LocalDateTime expireTime;
    private Object data;
}

步驟二、

ShopServiceImpl 新增此方法,利用單元測試進行緩存預熱

Redis緩存穿透、擊穿、雪崩問題及其解決方法

在測試類中

Redis緩存穿透、擊穿、雪崩問題及其解決方法

步驟三:正式代碼

ShopServiceImpl文章來源地址http://www.zghlxwxcb.cn/news/detail-432364.html

private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
public Shop queryWithLogicalExpire( Long id ) {
    String key = CACHE_SHOP_KEY + id;
    // 1.從redis查詢商鋪緩存
    String json = stringRedisTemplate.opsForValue().get(key);
    // 2.判斷是否存在
    if (StrUtil.isBlank(json)) {
        // 3.存在,直接返回
        return null;
    }
    // 4.命中,需要先把json反序列化為對象
    RedisData redisData = JSONUtil.toBean(json, RedisData.class);
    Shop shop = JSONUtil.toBean((JSONObject) redisData.getData(), Shop.class);
    LocalDateTime expireTime = redisData.getExpireTime();
    // 5.判斷是否過期
    if(expireTime.isAfter(LocalDateTime.now())) {
        // 5.1.未過期,直接返回店鋪信息
        return shop;
    }
    // 5.2.已過期,需要緩存重建
    // 6.緩存重建
    // 6.1.獲取互斥鎖
    String lockKey = LOCK_SHOP_KEY + id;
    boolean isLock = tryLock(lockKey);
    // 6.2.判斷是否獲取鎖成功
    if (isLock){
        CACHE_REBUILD_EXECUTOR.submit( ()->{

            try{
                //重建緩存
                this.saveShop2Redis(id,20L);
            }catch (Exception e){
                throw new RuntimeException(e);
            }finally {
                unlock(lockKey);
            }
        });
    }
    // 6.4.返回過期的商鋪信息
    return shop;
}

到了這里,關(guān)于Redis緩存穿透、擊穿、雪崩問題及其解決方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • 探討Redis緩存問題及解決方案:緩存穿透、緩存擊穿、緩存雪崩與緩存預熱(如何解決Redis緩存中的常見問題并提高應用性能)

    探討Redis緩存問題及解決方案:緩存穿透、緩存擊穿、緩存雪崩與緩存預熱(如何解決Redis緩存中的常見問題并提高應用性能)

    Redis是一種非常流行的開源緩存系統(tǒng),用于緩存數(shù)據(jù)以提高應用程序性能。但是,如果我們不注意一些緩存問題,Redis也可能會導致一些性能問題。在本文中,我們將探討Redis中的一些常見緩存問題,并提供解決方案。 緩存穿透指的是當一個請求嘗試訪問一個不存在于緩存中的

    2024年02月03日
    瀏覽(169)
  • Redis - 三大緩存問題(穿透、擊穿、雪崩)

    Redis - 三大緩存問題(穿透、擊穿、雪崩)

    概念: 查詢一個數(shù)據(jù)庫中也不存在的數(shù)據(jù),數(shù)據(jù)庫查詢不到數(shù)據(jù)也就不會寫入緩存,就會導致一直查詢數(shù)據(jù)庫 解決方法: 如果數(shù)據(jù)庫也查詢不到,就把空結(jié)果進行緩存 缺點是 - 消耗內(nèi)存 布隆過濾器的作用 :檢索一個元素是否在某個集合中 布隆過濾器由組成 : 位圖 + 若干

    2024年02月14日
    瀏覽(23)
  • Redis 如何解決緩存雪崩、緩存擊穿、緩存穿透難題

    Redis 如何解決緩存雪崩、緩存擊穿、緩存穿透難題

    Redis?作為一門熱門的緩存技術(shù),引入了緩存層,就會有緩存異常的三個問題,分別是緩存擊穿、緩存穿透、緩存雪崩。我們用本篇文章來講解下如何解決! 緩存擊穿 : 指的是緩存中的某個熱點數(shù)據(jù)過期了,但是此時大量的并發(fā)請求訪問這個key的值,此時因為緩存過期無法從

    2024年02月14日
    瀏覽(21)
  • redis緩存雪崩、穿透、擊穿解決方案

    redis緩存雪崩、穿透、擊穿解決方案

    關(guān)于緩存異常,我們常見的有三個問題:緩存雪崩、緩存擊穿、緩存穿透。這三個問題一旦發(fā)生,會導致大量請求直接落到數(shù)據(jù)庫層面。如果請求的并發(fā)量很大,會影響數(shù)據(jù)庫的運行,嚴重的會導致數(shù)據(jù)庫宕機。 為了避免緩存異常帶來的損失,我們需要了解每種異常的原因以

    2024年02月10日
    瀏覽(101)
  • Redis緩存問題(穿透, 擊穿, 雪崩, 污染, 一致性)

    Redis緩存問題(穿透, 擊穿, 雪崩, 污染, 一致性)

    目錄 1.什么是Redis緩存問題? 2.緩存穿透 3.緩存擊穿 4.緩存雪崩 5.緩存污染(或滿了) ? ?5.1?最大緩存設(shè)置多大 ? ?5.2?緩存淘汰策略 6.數(shù)據(jù)庫和緩存一致性 ? ?6.1?4種相關(guān)模式 ? ?6.2 方案:隊列+重試機制 ? ?6.3?方案:異步更新緩存(基于訂閱binlog的同步機制) 在高并發(fā)的業(yè)

    2024年02月12日
    瀏覽(20)
  • Redis什么是緩存穿透、擊穿、雪崩?如何解決

    Redis什么是緩存穿透、擊穿、雪崩?如何解決

    通常后端會采用Mysql等磁盤數(shù)據(jù)庫,可以持久化但是訪問慢,高并發(fā)時性能差,需要設(shè)置Nosql內(nèi)存型數(shù)據(jù)庫緩存:Redis等 但緩存可能出現(xiàn):緩存穿透、緩存擊穿、緩存雪崩等問題 查找數(shù)據(jù)的順序是:先查找緩存,再查找數(shù)據(jù)庫 當查找一個數(shù)據(jù)時,緩存沒有都會請求數(shù)據(jù)庫,當

    2024年02月09日
    瀏覽(28)
  • Redis:緩存擊穿、緩存穿透與緩存雪崩的區(qū)別、解決方案

    Redis:緩存擊穿、緩存穿透與緩存雪崩的區(qū)別、解決方案

    ? ? ? ? 近期學習redis相關(guān)原理,記錄一下開發(fā)過程中Redis的一些常見問題及應對方法。 一句話總結(jié):先查 redis發(fā)現(xiàn)沒數(shù)據(jù) ,再去 數(shù)據(jù)庫查發(fā)現(xiàn)還是沒數(shù)據(jù) 。 這種情況下 緩存永遠不會生效 ,數(shù)據(jù)庫將承擔巨大壓力。 ? ? ? ? 我們知道,redis的緩存作用,是在客戶端發(fā)起查

    2024年02月06日
    瀏覽(28)
  • Redis緩存問題:穿透,擊穿,雪崩,雙寫一致性等

    Redis緩存問題:穿透,擊穿,雪崩,雙寫一致性等

    在高并發(fā)場景下,數(shù)據(jù)庫往往是最薄弱的環(huán)節(jié),我們通常選擇使用 redis 來進行緩存,以起到緩沖作用,來降低數(shù)據(jù)庫的壓力,但是一旦緩存出現(xiàn)問題,也會導致數(shù)據(jù)庫瞬間壓力過大甚至崩潰,從而導致整個系統(tǒng)崩潰.今天就聊聊常見的 redis 緩存問題. 緩存擊穿 緩存擊穿一般指redis中的一

    2024年04月27日
    瀏覽(31)
  • redis中緩存雪崩,緩存穿透,緩存擊穿的原因以及解決方案

    redis中緩存雪崩,緩存穿透,緩存擊穿的原因以及解決方案

    在redis中,新,舊數(shù)據(jù)交替時候,舊數(shù)據(jù)進行了刪除,新數(shù)據(jù)沒有更新過來,造成在高并發(fā)環(huán)境下,大量請求查詢redis沒有數(shù)據(jù),直接查詢mysql,造成mysql的壓力驟增,給mysql造成極大的壓力,造成一連串的后續(xù)異常反應。 1.大多數(shù)系統(tǒng)設(shè)計者 考慮用加鎖 (最多的解決方案)或

    2024年02月15日
    瀏覽(36)
  • Redis 性能管理/優(yōu)化 雙一致性問題 緩存雪崩/擊穿/穿透

    Redis 性能管理/優(yōu)化 雙一致性問題 緩存雪崩/擊穿/穿透

    used_memory_rss:是Redis向操作系統(tǒng)申請的內(nèi)存。 used_memory:是Redis中的數(shù)據(jù)占用的內(nèi)存。 mem_fragmentation_ratio:內(nèi)存碎片率。 used_memory_peak:redis內(nèi)存使用的峰值。 內(nèi)存碎片如何產(chǎn)生的? Redis內(nèi)部有自己的內(nèi)存管理器,為了提高內(nèi)存使用的效率,來對內(nèi)存的申請和釋放進行管理。

    2024年02月11日
    瀏覽(37)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包