曰本毛片va看到爽不卡_亚洲色图欧美激情_九九久久精品视频_亚洲综合色在线


 

day03-商家查詢緩存02 今日熱聞
發布時間:2023-04-20 23:46:45 文章來源:博客園
功能02-商鋪查詢緩存02知識補充(1)緩存穿透https://blog.csdn.net/qq_45637260/article/details/125866738緩存穿透(cachepe
功能02-商鋪查詢緩存02知識補充(1)緩存穿透

https://blog.csdn.net/qq_45637260/article/details/125866738

緩存穿透(cache penetration)是指用戶訪問的數據既不在緩存當中,也不在數據庫中。出于容錯的考慮,如果從底層數據庫查詢不到數據,則不寫入緩存。這就導致每次請求都會到底層數據庫進行查詢,緩存也失去了意義。當高并發或有人利用不存在的Key頻繁攻擊時,數據庫的壓力驟增,甚至崩潰,這就是緩存穿透問題。

簡單地說,緩存穿透是指用戶請求的數據在緩存和數據庫中都不存在,則每次請求都會打到數據庫中,給數據庫帶來巨大壓力。


【資料圖】

常見的兩種解決方案

(1)緩存空對象:是指在持久層沒有命中的情況下,對key進行set (key,null)。

緩存空對象會有兩個問題:

value為null 不代表不占用內存空間,空值做了緩存,意味著緩存層中存了更多的鍵,需要更多的內存空間,比較有效的方法是針對這類數據設置一個較短的過期時間,讓其自動剔除。

緩存層和存儲層的數據會有一段時間窗口的不一致,可能會對業務有一定影響。例如過期時間設置為5分鐘,如果此時存儲層添加了這個數據,那此段時間就會出現緩存層和存儲層數據的不一致,此時可以利用消息系統或者其他方式清除掉緩存層中的空對象。

(2)布隆過濾器:

在訪問緩存層和存儲層之前,將存在的key用布隆過濾器提前保存起來,做第一層攔截,當收到一個對key請求時,先用布隆過濾器驗證是key否存在,如果存在再進入緩存層、存儲層。

可以使用bitmap做布隆過濾器。這種方法適用于數據命中不高、數據相對固定、實時性低的應用場景,代碼維護較為復雜,但是緩存空間占用少。

布隆過濾器實際上是一個很長的二進制向量和一系列隨機映射函數。布隆過濾器可以用于檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困難。

布隆過濾器攔截的算法描述:

初始狀態時,BloomFilter是一個長度為m的位數組,每一位都置為0。添加元素x時,x使用k個hash函數得到k個hash值,對m取余,對應的bit位設置為1。

判斷y是否屬于這個集合,對y使用k個哈希函數得到k個哈希值,對m取余,所有對應的位置都是1,則認為y屬于該集合(哈希沖突,可能存在誤判),否則就認為y不屬于該集合??梢酝ㄟ^增加哈希函數和增加二進制位數組的長度來降低錯報率

兩種方案的比較:

緩存穿透的方案使用場景維護成本
緩存空對象1.數據命中率不高 2.數據頻繁變化實時性高1.代碼維護簡單 2.需要過多的緩存空間 3.數據不一致
布隆過濾器1.數據命中不高 2.數據相對固定實時性低1.代碼維護復雜 2.緩存空間占用少

緩存穿透的解決方案還有:

(2)緩存雪崩

緩存雪崩

在使用緩存時,通常會對緩存設置過期時間,一方面目的是保持緩存與數據庫數據的一致性,另一方面是減少冷緩存占用過多的內存空間。但當緩存中大量熱點緩存采用了相同的實效時間,就會導致緩存在某一個時刻同時實效,請求全部轉發到數據庫,從而導致數據庫壓力驟增,甚至宕機。從而形成一系列的連鎖反應,造成系統崩潰等情況,這就是緩存雪崩(Cache Avalanche)。

簡單地說,緩存雪崩是指在同一時間段大量的熱點key同時失效,或者Redis服務宕機,導致大量請求到達數據庫,給數據庫帶來巨大壓力。

解決方案

給不同的key的TTL添加隨機值(比如隨機1-5分鐘),讓key均勻地失效利用redis集群提高服務的可用性(提高高可用性)給緩存業務添加熔斷、降級、限流策略給業務添加多級緩存(3)緩存擊穿

緩存擊穿

如果有一個熱點key,在不停的扛著大并發,在這個key失效的瞬間,持續的大并發請求就會擊破緩存,直接請求到數據庫,好像蠻力擊穿一樣。這種情況就是緩存擊穿(Cache Breakdown)。

緩存擊穿問題也叫做熱點key問題,簡單來說,就是一個被高并發訪問并且緩存重建業務較復雜的key突然失效了,無數的請求訪問在瞬間給數據庫帶來巨大的沖擊。

從定義上可以看出,緩存擊穿和緩存雪崩很類似,只不過是緩存擊穿是一個熱點key失效,而緩存雪崩是大量熱點key失效。因此,可以將緩存擊穿看作是緩存雪崩的一個子集。

解決方案

方案一:使用互斥鎖(Mutex Key),只讓一個線程構建緩存,其他線程等待構建緩存執行完畢,重新從緩存中獲取數據。單機通過synchronized或lock來處理,分布式環境采用分布式鎖。

方案二:邏輯過期。熱點數據不設置過期時間,只在value中設置邏輯上的過期時間。后臺異步更新緩存,適用于不嚴格要求緩存一致性的場景。

兩種方案的對比:

3.功能02-商鋪查詢緩存3.4查詢商鋪id的緩存穿透問題3.4.3需求分析

解決查詢商鋪查詢可能存在的緩存穿透問題:當訪問不存在的店鋪時,請求會直接打到數據庫上,并且redis緩存永遠不會生效。

這里使用緩存空對象的方式來解決。

3.4.4代碼實現

(1)修改ShopServiceImpl.java的queryById方法

@Overridepublic Result queryById(Long id) {    String key = CACHE_SHOP_KEY + id;    //1.從redis中查詢商鋪緩存    String shopJson = stringRedisTemplate.opsForValue().get(key);    //2.判斷緩存是否命中    if (StrUtil.isNotBlank(shopJson)) {        //2.1若命中,直接返回商鋪信息        Shop shop = JSONUtil.toBean(shopJson, Shop.class);        return Result.ok(shop);    }    //判斷命中的是否是redis的空值    if (shopJson != null) {        return Result.fail("店鋪不存在!");    }    //2.2未命中,根據id查詢數據庫,判斷商鋪是否存在數據庫中    Shop shop = getById(id);    if (shop == null) {        //2.2.1不存在,防止緩存穿透,將空值存入redis,TTL設置為2min        stringRedisTemplate.opsForValue().set(key, "",                CACHE_NULL_TTL, TimeUnit.MINUTES);        //返回錯誤信息        return Result.fail("店鋪不存在!");    }    //2.2.2存在,則將商鋪數據寫入redis中    stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),            CACHE_SHOP_TTL, TimeUnit.MINUTES);    return Result.ok(shop);}

(2)測試,訪問一個緩存和數據庫都不存在的數據:

可以看到redis已經緩存了一個空值

之后再訪問該數據,只要redis的空值對沒有過期,就不會訪問到數據庫,從而起到保護數據庫的作用。

3.5查詢商鋪id的緩存擊穿問題

當查詢店鋪id時,可能會出現該店鋪id對應的緩存失效,從而大量請求發送到數據庫的情況,這里使用兩種方案分別解決該問題。

3.5.1基于互斥鎖方案解決3.5.1.1需求分析

修改根據id查詢商鋪的業務,基于互斥鎖方式來解決緩存擊穿問題。

如下,當出現緩存擊穿問題,首先需要判斷當前的線程是否能夠獲取鎖:

若可以,則進行緩存重建(將數據庫數據重新寫入緩存中),然后釋放鎖。如果不能,則線程等待一段時間,然后再判斷緩存是否能命中。如果未命中,則重復獲取鎖的流程,直到緩存命中,或者獲得鎖,重建緩存。

根據redis的setnx命令,當setnx設置某個key之后,如果該key存在,則其他線程無法設置該key。

我們可以根據這個特性,作為一個lock的邏輯標志,當一個線程setnx某個key后,代表獲取了“鎖”。當刪除這個key時,代表釋放“鎖”,這樣其他線程就可以重新獲取“鎖”。此外,可以對該key設置一個有效期,防止刪除key失敗,產生“死鎖”。

3.5.1.2代碼實現

(1)修改 ShopServiceImpl.java

package com.hmdp.service.impl;import .../** * 服務實現類 * * @author 李 * @version 1.0 */@Servicepublic class ShopServiceImpl extends ServiceImpl        implements IShopService {    @Resource    StringRedisTemplate stringRedisTemplate;    @Override    public Result queryById(Long id) {        Shop shop = queryWithMutex(id);        if (shop == null) {            return Result.fail("店鋪不存在!");        }        return Result.ok(shop);    }    //緩存穿透(存儲空對象)+緩存擊穿解決(互斥鎖解決)    public Shop queryWithMutex(Long id) {        String key = CACHE_SHOP_KEY + id;        //從redis中查詢商鋪緩存        String shopJson = stringRedisTemplate.opsForValue().get(key);        //判斷緩存是否命中        if (StrUtil.isNotBlank(shopJson)) {            //命中,直接返回商鋪信息            return JSONUtil.toBean(shopJson, Shop.class);        }        //判斷命中的是否是redis的空值(緩存擊穿解決)        if (shopJson != null) {            return null;        }        //未命中,嘗試獲取互斥鎖        String lockKey = "lock:shop:" + id;        boolean isLock = false;        Shop shop = null;        try {            //獲取互斥鎖            isLock = tryLock(lockKey);            //判斷是否獲取成功            if (!isLock) {//失敗                //等待并重試                Thread.sleep(50);                //直到緩存命中,或者獲取到鎖                return queryWithMutex(id);            }            //獲取鎖成功,開始重建緩存            //根據id查詢數據庫,判斷商鋪是否存在數據庫中            shop = getById(id);            //模擬重建緩存的延遲-----------            Thread.sleep(200);            if (shop == null) {                //不存在,防止緩存穿透,將空值存入redis,TTL設置為2min                stringRedisTemplate.opsForValue().set(key, "",                        CACHE_NULL_TTL, TimeUnit.MINUTES);                //返回錯誤信息                return null;            }            //存在,則將商鋪數據寫入redis中            stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),                    CACHE_SHOP_TTL, TimeUnit.MINUTES);        } catch (InterruptedException e) {            throw new RuntimeException(e);        } finally {            //釋放互斥鎖            unLock(lockKey);        }        //返回從緩存或數據庫中查到的數據        return shop;    }    //緩存穿透方案//    public Shop queryWithPassThrough(Long id) {//        String key = CACHE_SHOP_KEY + id;//        //1.從redis中查詢商鋪緩存//        String shopJson = stringRedisTemplate.opsForValue().get(key);//        //2.判斷緩存是否命中//        if (StrUtil.isNotBlank(shopJson)) {//            //2.1若命中,直接返回商鋪信息//            return JSONUtil.toBean(shopJson, Shop.class);//        }//        //判斷命中的是否是redis的空值//        if (shopJson != null) {//            return null;//        }//        //2.2未命中,根據id查詢數據庫,判斷商鋪是否存在數據庫中//        Shop shop = getById(id);//        if (shop == null) {//            //2.2.1不存在,防止緩存穿透,將空值存入redis,TTL設置為2min//            stringRedisTemplate.opsForValue().set(key, "",//                    CACHE_NULL_TTL, TimeUnit.MINUTES);//            //返回錯誤信息//            return null;//        }//        //2.2.2存在,則將商鋪數據寫入redis中//        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),//                CACHE_SHOP_TTL, TimeUnit.MINUTES);//        return shop;//    }    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);    }    @Override    @Transactional    public Result update(Shop shop) {        Long id = shop.getId();        if (id == null) {            return Result.fail("店鋪id不能為空");        }        //1.更新數據庫        updateById(shop);        //2.刪除redis緩存        stringRedisTemplate.delete(CACHE_SHOP_KEY + id);        return Result.ok();    }}

(2)使用jemeter模擬高并發的情況:

5秒發起1000個請求線程:

模擬http請求:

全部請求成功,獲取到數據:

在服務器的控制臺中可以看到:對于數據庫的請求只觸發了一次,證明在高并發的場景下,只有一個線程對數據庫發起請求,并對redis對應的緩存重新設置。

3.5.2基于邏輯過期方案解決
關鍵詞:

樂活HOT

娛樂LOVE

曰本毛片va看到爽不卡_亚洲色图欧美激情_九九久久精品视频_亚洲综合色在线
  • <li id="yeaqi"><button id="yeaqi"></button></li>
  • <fieldset id="yeaqi"></fieldset>
    <fieldset id="yeaqi"><table id="yeaqi"></table></fieldset>
    • 热99这里只有精品| 精品视频一区二区在线| 日韩福利视频在线| 人妻久久久一区二区三区| 蜜桃视频成人在线观看| 91网址在线观看精品| 男生操女生视频在线观看| 五月婷婷狠狠操| 中文久久久久久| 小泽玛利亚视频在线观看| 黄色av免费在线播放| 免费看a级黄色片| 牛夜精品久久久久久久| 日韩av手机版| 国产乱女淫av麻豆国产| 在线观看中文av| 自拍一级黄色片| mm131午夜| 青青青青在线视频| koreanbj精品视频一区| 成人黄色片视频| 日本特黄a级片| www.欧美激情.com| 国产内射老熟女aaaa| 国产欧美精品aaaaaa片| 九一国产精品视频| 欧美日韩亚洲一二三| 亚洲综合色在线观看| 午夜免费一级片| 成人手机在线播放| 自慰无码一区二区三区| 色综合天天色综合| 中文字幕第三区| 丁香花在线影院观看在线播放| 波多野结衣综合网| 免费黄色一级网站| 中文字幕av导航| 大荫蒂性生交片| 日韩一级免费在线观看| 一区二区久久精品| 亚洲国产精品成人天堂| 国产三级日本三级在线播放| 91香蕉视频免费看| 免费在线观看亚洲视频 | 亚洲不卡中文字幕无码| 日本人视频jizz页码69| www.黄色网址.com| 免费无码av片在线观看| 日本中文字幕在线不卡| 国产原创popny丨九色 | 欧美日韩一区二区三区69堂| 中文字幕第50页| 成人一级片网站| 天堂av免费看| 日韩精品一区二区三区不卡| 天天综合五月天| 日本男人操女人| 喜爱夜蒲2在线| 久久久久久久片| 少妇一晚三次一区二区三区| 中文字幕在线导航| avav在线播放| 亚洲高清视频免费| 免费av网址在线| 99热这里只有精品免费| av在线网址导航| 日本福利视频导航| 国产99久久九九精品无码| 亚洲一级片av| 欧在线一二三四区| 18禁裸男晨勃露j毛免费观看| 亚洲欧美视频二区| 那种视频在线观看| www.18av.com| 91在线第一页| 在线观看高清免费视频| 免费看国产曰批40分钟| 国产一级黄色录像片| 五月天av在线播放| 丁香啪啪综合成人亚洲| 男人天堂手机在线视频| 三年中文高清在线观看第6集| 五月天婷婷激情视频| 欧美日韩在线一| 久久久久久人妻一区二区三区| 91网址在线观看精品| 手机看片一级片| 能看的毛片网站| 欧美丰满熟妇bbbbbb百度| 国产尤物av一区二区三区| 一级做a爱视频| 手机av在线免费| 中文字幕国产传媒| 少妇高清精品毛片在线视频| av动漫在线看| 阿v天堂2017| cao在线观看| 久久手机在线视频| 免费看日本黄色| 欧美做暖暖视频| 国产在线观看欧美| 日韩成人午夜影院| 欧美交换配乱吟粗大25p| 青娱乐精品在线| 天天综合中文字幕| 交换做爰国语对白| 超碰在线免费观看97| 免费国产成人看片在线| 中文字幕精品在线播放| 18视频在线观看娇喘| 国产91porn| 男人添女人下部视频免费| 波多野结衣与黑人| 青春草国产视频| 亚洲 高清 成人 动漫| 国产极品美女高潮无套久久久| av动漫免费看| 别急慢慢来1978如如2| 中国黄色片免费看| 欧美日韩久久婷婷| 欧美一区二区三区综合| 久久久久久免费看| 日本不卡在线观看视频| 别急慢慢来1978如如2| 色一情一区二区三区| 日韩第一页在线观看| youjizz.com在线观看| 欧美日本视频在线观看| 欧美激情成人网| 中日韩av在线播放| 91看片淫黄大片91| 久久精品视频16| 91在线视频观看免费| 日韩va在线观看| 91看片淫黄大片91| 亚洲午夜精品久久久久久人妖| 国产xxxxx视频| 不用播放器的免费av| 少妇久久久久久被弄到高潮| 国产伦精品一区二区三区四区视频_ | 亚洲综合伊人久久| 免费看日b视频| 116极品美女午夜一级| www.久久91| www.亚洲成人网| 久久精品午夜福利| 手机在线观看日韩av| 欧美大片在线播放| 亚洲娇小娇小娇小| 欧美久久在线观看| 手机在线看福利| 黄色片免费在线观看视频| 欧美韩国日本在线| 日本免费在线视频观看| 亚洲中文字幕无码中文字| 亚洲欧美手机在线| 一二三四视频社区在线| 不卡中文字幕在线观看| 水蜜桃色314在线观看| 亚洲一区二区在线视频观看| 久久久久久久9| 欧美成年人视频在线观看| 青春草国产视频| 18岁视频在线观看| 特大黑人娇小亚洲女mp4| 50路60路老熟妇啪啪| 欧美爱爱视频网站| 欧美 国产 小说 另类| 久久免费视频2| 国产一区视频免费观看| 黄色一级大片免费| 国产色视频在线播放| 精品视频免费在线播放| 九九热视频免费| 别急慢慢来1978如如2| www.激情网| 国产精品嫩草影院8vv8 | 欧美专区第二页| 日韩精品一区二区三区色欲av| 91成人在线视频观看| 91精品无人成人www| 一女被多男玩喷潮视频| youjizz.com亚洲| 精品999在线| av免费中文字幕| 日韩日韩日韩日韩日韩| 亚洲综合在线一区二区| 别急慢慢来1978如如2| 国精产品一区一区三区视频| 91免费视频黄| 国产成人美女视频| 人人爽人人av| 日本网站免费在线观看| 99国产精品白浆在线观看免费| 亚洲综合在线一区二区| 中文字幕亚洲欧洲| 亚洲精品怡红院| 日韩中文字幕二区| 国产最新免费视频| 欧美成人三级在线视频|