最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis緩存異常常用解決方案總結(jié)

 更新時(shí)間:2023年12月13日 11:53:14   作者:cxzm_java  
Redis緩存異常問(wèn)題分別是緩存雪崩,緩存預(yù)熱,緩存穿透,緩存降級(jí),緩存擊穿,本文主要介紹了Redis緩存異常常用解決方案總結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下

前言

Redis緩存異常問(wèn)題分別是:1.緩存雪崩。2.緩存預(yù)熱。3.緩存穿透。4.緩存降級(jí)。5.緩存擊穿,以及對(duì)應(yīng)Redis緩存異常問(wèn)題解決方案。

1.緩存雪崩

1.1、什么是緩存雪崩

如果緩存集中在一段時(shí)間內(nèi)失效,發(fā)生大量的緩存穿透,所有的查詢都落在數(shù)據(jù)庫(kù)上,造成了緩存雪崩由于原有緩存失效,新緩存未到期間所有原本應(yīng)該訪問(wèn)緩存的請(qǐng)求都去查詢數(shù)據(jù)庫(kù)了,而對(duì)數(shù)據(jù)庫(kù)CPU和內(nèi)存造成巨大壓力,嚴(yán)重的會(huì)造成數(shù)據(jù)庫(kù)宕機(jī)。

舉例來(lái)說(shuō), 我們?cè)跍?zhǔn)備一項(xiàng)搶購(gòu)的促銷運(yùn)營(yíng)活動(dòng),活動(dòng)期間將帶來(lái)大量的商品信息、庫(kù)存等相關(guān)信息的查詢。

為了避免商品數(shù)據(jù)庫(kù)的壓力,將商品數(shù)據(jù)放入緩存中存儲(chǔ)。不巧的是,搶購(gòu)活動(dòng)期間,大量的熱門商品緩存同時(shí)失

效過(guò)期了,導(dǎo)致很大的查詢流量落到了數(shù)據(jù)庫(kù)之上,對(duì)于數(shù)據(jù)庫(kù)來(lái)說(shuō)造成很大的壓力。

1.2、解決方案

1、加鎖排隊(duì)

mutex互斥鎖解決,Redis的SETNX去set一個(gè)mutex key,當(dāng)操作返回成功時(shí),再進(jìn)行加載數(shù)據(jù)庫(kù)的操作并回設(shè)緩存,否則,就重試整個(gè)get緩存的方法。

2、數(shù)據(jù)預(yù)熱

緩存預(yù)熱就是系統(tǒng)上線后,將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶請(qǐng)求的時(shí)候,先查詢數(shù)據(jù)庫(kù),然后再將數(shù)據(jù)緩存的問(wèn)題。用戶直接查詢事先被預(yù)熱的緩存數(shù)據(jù)??梢酝ㄟ^(guò)緩存reload機(jī)制,預(yù)先去更新緩存,再即將發(fā)生大并發(fā)訪問(wèn)前手動(dòng)觸發(fā)加載緩存不同的key。

3、雙層緩存策略

C1為原始緩存,C2為拷貝緩存,C1失效時(shí),可以訪問(wèn)C2,C1緩存失效時(shí)間設(shè)置為短期,C2設(shè)置為長(zhǎng)期。

4、定時(shí)更新緩存策略

實(shí)效性要求不高的緩存,容器啟動(dòng)初始化加載,采用定時(shí)任務(wù)更新或移除緩存。

5、設(shè)置不同的過(guò)期時(shí)間。

讓緩存失效的時(shí)間點(diǎn)盡量均勻。

2.緩存預(yù)熱

2.1、什么是緩存預(yù)熱

緩存預(yù)熱就是系統(tǒng)上線后,將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶請(qǐng)求的時(shí)候,先查詢數(shù)據(jù)庫(kù),然后再將數(shù)據(jù)緩存的問(wèn)題。用戶直接查詢事先被預(yù)熱的緩存數(shù)據(jù)。

如圖所示:

如果不進(jìn)行預(yù)熱, 那么 Redis 初識(shí)狀態(tài)數(shù)據(jù)為空,系統(tǒng)上線初期,對(duì)于高并發(fā)的流量,都會(huì)訪問(wèn)到數(shù)據(jù)庫(kù)中, 對(duì)數(shù)據(jù)庫(kù)造成流量的壓力。

2.2、解決方案

  • 數(shù)據(jù)量不大的時(shí)候,工程啟動(dòng)的時(shí)候進(jìn)行加載緩存動(dòng)作;

  • 數(shù)據(jù)量大的時(shí)候,設(shè)置一個(gè)定時(shí)任務(wù)腳本,進(jìn)行緩存的刷新;

  • 數(shù)據(jù)量太大的時(shí)候,優(yōu)先保證熱點(diǎn)數(shù)據(jù)進(jìn)行提前加載到緩存。

3.緩存穿透

3.1、什么是緩存穿透

緩存穿透是指用戶查詢數(shù)據(jù),在數(shù)據(jù)庫(kù)沒有,自然在緩存中也不會(huì)有。這樣就導(dǎo)致用戶查詢的時(shí)候,在緩存中找不到對(duì)應(yīng)key的value,每次都要去數(shù)據(jù)庫(kù)再查詢一遍,然后返回空(相當(dāng)于進(jìn)行了兩次無(wú)用的查詢)。這樣請(qǐng)求就繞過(guò)緩存直接查數(shù)據(jù)庫(kù)。

3.2、解決方案

1、緩存空對(duì)象

簡(jiǎn)單粗暴的方法,如果一個(gè)查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在,還是系統(tǒng)故障),我們?nèi)匀?strong>把這個(gè)空結(jié)果進(jìn)行緩存,但它的過(guò)期時(shí)間會(huì)很短,最長(zhǎng)不超過(guò)五分鐘。

2、布隆過(guò)濾器

優(yōu)勢(shì):占用內(nèi)存空間很小,位存儲(chǔ);性能特別高,使用key的hash判斷key存不存在。

將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè)bitmap攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力。

4.緩存降級(jí)

降級(jí)的情況,就是緩存失效或者緩存服務(wù)掛掉的情況下,我們也不去訪問(wèn)數(shù)據(jù)庫(kù)。

我們直接訪問(wèn)內(nèi)存部分?jǐn)?shù)據(jù)緩存或者直接返回默認(rèn)數(shù)據(jù)

舉例來(lái)說(shuō):

對(duì)于應(yīng)用的首頁(yè),一般是訪問(wèn)量非常大的地方,首頁(yè)里面往往包含了部分推薦商品的展示信息。這些推薦商品都會(huì)放到緩存中進(jìn)行存儲(chǔ),同時(shí)我們?yōu)榱吮苊饩彺娴漠惓G闆r,對(duì)熱點(diǎn)商品數(shù)據(jù)也存儲(chǔ)到了內(nèi)存中。同時(shí)內(nèi)存中還保留了一些默認(rèn)的商品信息。

降級(jí)一般是有損的操作,所以盡量減少降級(jí)對(duì)于業(yè)務(wù)的影響程度

5.緩存擊穿

5.1、什么是緩存擊穿

緩存擊穿是指緩存中沒有但數(shù)據(jù)庫(kù)中有的數(shù)據(jù)(一般是緩存時(shí)間到期),這時(shí)由于并發(fā)用戶特別多,同時(shí)讀緩存沒

讀到數(shù)據(jù),又同時(shí)去數(shù)據(jù)庫(kù)去取數(shù)據(jù),引起數(shù)據(jù)庫(kù)壓力瞬間增大,造成過(guò)大壓力。

5.2、會(huì)帶來(lái)什么問(wèn)題

會(huì)造成某一時(shí)刻數(shù)據(jù)庫(kù)請(qǐng)求量過(guò)大,壓力劇增。

5.3、解決方案

5.3.1.使用互斥鎖(mutex key)

這種解決方案思路比較簡(jiǎn)單,就是只讓一個(gè)線程構(gòu)建緩存,其他線程等待構(gòu)建緩存的線程執(zhí)行完,重新從緩存獲取數(shù)據(jù)就可以了。

如果是單機(jī),可以用synchronized或者lock來(lái)處理;

如果是分布式環(huán)境可以用分布式鎖就可以了(分布式鎖,可以用memcache的add, redis的setnx, zookeeper的添加節(jié)點(diǎn)操作)。

5.3.2.永遠(yuǎn)不過(guò)期

  • 從redis上看,確實(shí)沒有設(shè)置過(guò)期時(shí)間,這就保證了,不會(huì)出現(xiàn)熱點(diǎn)key過(guò)期問(wèn)題,也就是“物理”不過(guò)期。

  • 從功能上看,如果不過(guò)期,那不就成靜態(tài)的了嗎?所以我們把過(guò)期時(shí)間存在key對(duì)應(yīng)的value里,如果發(fā)現(xiàn)要過(guò)期了,通過(guò)一個(gè)后臺(tái)的異步線程進(jìn)行緩存的構(gòu)建,也就是“邏輯”過(guò)期。

5.3.3.緩存屏障

該方法類似于方法一

使用countDownLatch和atomicInteger.compareAndSet()方法,實(shí)現(xiàn)輕量級(jí)鎖。

 public class MyCache{
 ?
     private ConcurrentHashMap<String, String> map;
 ?
     private CountDownLatch countDownLatch;
 ?
     private AtomicInteger atomicInteger;
 ?
     public MyCache(ConcurrentHashMap<String, String> map, CountDownLatch countDownLatch,
                    AtomicInteger atomicInteger) {
         this.map = map;
         this.countDownLatch = countDownLatch;
         this.atomicInteger = atomicInteger;
     }
 ?
     public String get(String key){
 ?
         String value = map.get(key);
         if (value != null){
             System.out.println(Thread.currentThread().getName()+"\t 線程獲取value值 value="+value);
             return value;
         }
         // 如果沒獲取到值
         // 首先嘗試獲取token,然后去查詢db,初始化化緩存;
         // 如果沒有獲取到token,超時(shí)等待
         if (atomicInteger.compareAndSet(0,1)){
             System.out.println(Thread.currentThread().getName()+"\t 線程獲取token");
             return null;
         }
 ?
         // 其他線程超時(shí)等待
         try {
             System.out.println(Thread.currentThread().getName()+"\t 線程沒有獲取token,等待中。。。");
             countDownLatch.await();
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         // 初始化緩存成功,等待線程被喚醒
         // 等待線程等待超時(shí),自動(dòng)喚醒
         System.out.println(Thread.currentThread().getName()+"\t 線程被喚醒,獲取value ="+map.get("key"));
         return map.get(key);
     }
 ?
     public void put(String key, String value){
 ?
         try {
             Thread.sleep(2000);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
 ?
         map.put(key, value);
 ?
         // 更新狀態(tài)
         atomicInteger.compareAndSet(1, 2);
 ?
         // 通知其他線程
         countDownLatch.countDown();
         System.out.println();
         System.out.println(Thread.currentThread().getName()+"\t 線程初始化緩存成功!value ="+map.get("key"));
     }
 ?
 }
 ?
 public  class MyThread implements Runnable{
 ?
     private MyCache myCache;
 ?
     public MyThread(MyCache myCache) {
         this.myCache = myCache;
     }
 ?
     @Override
     public void run() {
         String value = myCache.get("key");
         if (value == null){
             myCache.put("key","value");
         }
 ?
     }
 }
 ?
 public class CountDownLatchDemo {
     public static void main(String[] args) {
 ?
         MyCache myCache = new MyCache(new ConcurrentHashMap<>(), new CountDownLatch(1), new AtomicInteger(0));
 ?
         MyThread myThread = new MyThread(myCache);
 ?
         ExecutorService executorService = Executors.newFixedThreadPool(5);
         for (int i = 0; i < 5; i++) {
             executorService.execute(myThread);
         }
     }
 }

到此這篇關(guān)于Redis緩存異常常用解決方案總結(jié)的文章就介紹到這了,更多相關(guān)Redis緩存異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis 數(shù)據(jù)類型Streams詳解

    Redis 數(shù)據(jù)類型Streams詳解

    Redis Streams是Redis 5.0新增的數(shù)據(jù)類型,提供了一種日志結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)方式,這種類型適合用于構(gòu)建消息隊(duì)列、事件日志和處理時(shí)間序列數(shù)據(jù)的應(yīng)用,本文介紹Redis 數(shù)據(jù)類型Streams相關(guān)知識(shí),感興趣的朋友一起看看吧
    2024-10-10
  • Redis字典實(shí)現(xiàn)、Hash鍵沖突及漸進(jìn)式rehash詳解

    Redis字典實(shí)現(xiàn)、Hash鍵沖突及漸進(jìn)式rehash詳解

    這篇文章主要介紹了Redis字典實(shí)現(xiàn)、Hash鍵沖突以及漸進(jìn)式rehash的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • 基于Redis的ZSET實(shí)現(xiàn)用戶邀請(qǐng)排行榜

    基于Redis的ZSET實(shí)現(xiàn)用戶邀請(qǐng)排行榜

    本文主要介紹了在項(xiàng)目中實(shí)現(xiàn)用戶邀請(qǐng)功能并基于積分進(jìn)行排名的解決方案,使用了Redis的ZSET數(shù)據(jù)結(jié)構(gòu)和Redisson的RLock進(jìn)行加鎖以避免并發(fā)問(wèn)題,感興趣的可以了解一下
    2025-11-11
  • 淺談Redis高并發(fā)緩存架構(gòu)性能優(yōu)化實(shí)戰(zhàn)

    淺談Redis高并發(fā)緩存架構(gòu)性能優(yōu)化實(shí)戰(zhàn)

    本文主要介紹了淺談Redis高并發(fā)緩存架構(gòu)性能優(yōu)化實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • Redis發(fā)布訂閱和實(shí)現(xiàn).NET客戶端詳解

    Redis發(fā)布訂閱和實(shí)現(xiàn).NET客戶端詳解

    發(fā)布訂閱在應(yīng)用級(jí)其作用是為了減少依賴關(guān)系,通常也叫觀察者模式。主要是把耦合點(diǎn)單獨(dú)抽離出來(lái)作為第三方,隔離易變化的發(fā)送方和接收方。下面這篇文章主要給大家介紹了關(guān)于Redis發(fā)布訂閱和實(shí)現(xiàn).NET客戶端的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Redis學(xué)習(xí)教程之命令的執(zhí)行過(guò)程詳解

    Redis學(xué)習(xí)教程之命令的執(zhí)行過(guò)程詳解

    這篇文章主要給大家介紹了關(guān)于Redis學(xué)習(xí)教程之命令的執(zhí)行過(guò)程的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • 最新評(píng)論

    渭南市| 曲麻莱县| 瑞安市| 乌兰浩特市| 阿尔山市| 婺源县| 行唐县| 黔南| 英吉沙县| 玛多县| 景泰县| 阳江市| 仪陇县| 扎囊县| 金平| 阳原县| 微山县| 定兴县| 靖江市| 梧州市| 沧源| 盐池县| 彭州市| 青川县| 崇左市| 潼关县| 衡阳市| 禄丰县| 郧西县| 靖西县| 邵阳县| 遂平县| 桑植县| 永吉县| 措美县| 汉川市| 海原县| 株洲县| 老河口市| 称多县| 繁峙县|