91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何設(shè)計(jì)一個(gè)緩存系統(tǒng)?

數(shù)據(jù)分析與開(kāi)發(fā) ? 來(lái)源:CSDN ? 作者:zeb_perfect ? 2021-02-08 11:40 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

設(shè)計(jì)一個(gè)緩存系統(tǒng),不得不要考慮的問(wèn)題就是:緩存穿透、緩存擊穿與失效時(shí)的雪崩效應(yīng)。

緩存穿透

緩存穿透是指查詢(xún)一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)被動(dòng)寫(xiě)的,并且出于容錯(cuò)考慮,如果從存儲(chǔ)層查不到數(shù)據(jù)則不寫(xiě)入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到存儲(chǔ)層去查詢(xún),失去了緩存的意義。在流量大時(shí),可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應(yīng)用,這就是漏洞。

解決方案

有很多種方法可以有效地解決緩存穿透問(wèn)題,最常見(jiàn)的則是采用布隆過(guò)濾器,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被 這個(gè)bitmap攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢(xún)壓力。另外也有一個(gè)更為簡(jiǎn)單粗暴的方法(我們采用的就是這種),如果一個(gè)查詢(xún)返回的數(shù)據(jù)為空(不管是數(shù) 據(jù)不存在,還是系統(tǒng)故障),我們?nèi)匀话堰@個(gè)空結(jié)果進(jìn)行緩存,但它的過(guò)期時(shí)間會(huì)很短,最長(zhǎng)不超過(guò)五分鐘。

緩存雪崩

緩存雪崩是指在我們?cè)O(shè)置緩存時(shí)采用了相同的過(guò)期時(shí)間,導(dǎo)致緩存在某一時(shí)刻同時(shí)失效,請(qǐng)求全部轉(zhuǎn)發(fā)到DB,DB瞬時(shí)壓力過(guò)重雪崩。

解決方案

緩存失效時(shí)的雪崩效應(yīng)對(duì)底層系統(tǒng)的沖擊非??膳?。大多數(shù)系統(tǒng)設(shè)計(jì)者考慮用加鎖或者隊(duì)列的方式保證緩存的單線(xiàn) 程(進(jìn)程)寫(xiě),從而避免失效時(shí)大量的并發(fā)請(qǐng)求落到底層存儲(chǔ)系統(tǒng)上。這里分享一個(gè)簡(jiǎn)單方案就時(shí)講緩存失效時(shí)間分散開(kāi),比如我們可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值,比如1-5分鐘隨機(jī),這樣每一個(gè)緩存的過(guò)期時(shí)間的重復(fù)率就會(huì)降低,就很難引發(fā)集體失效的事件。

緩存擊穿

對(duì)于一些設(shè)置了過(guò)期時(shí)間的key,如果這些key可能會(huì)在某些時(shí)間點(diǎn)被超高并發(fā)地訪(fǎng)問(wèn),是一種非?!盁狳c(diǎn)”的數(shù)據(jù)。這個(gè)時(shí)候,需要考慮一個(gè)問(wèn)題:緩存被“擊穿”的問(wèn)題,這個(gè)和緩存雪崩的區(qū)別在于這里針對(duì)某一key緩存,前者則是很多key。

緩存在某個(gè)時(shí)間點(diǎn)過(guò)期的時(shí)候,恰好在這個(gè)時(shí)間點(diǎn)對(duì)這個(gè)Key有大量的并發(fā)請(qǐng)求過(guò)來(lái),這些請(qǐng)求發(fā)現(xiàn)緩存過(guò)期一般都會(huì)從后端DB加載數(shù)據(jù)并回設(shè)到緩存,這個(gè)時(shí)候大并發(fā)的請(qǐng)求可能會(huì)瞬間把后端DB壓垮。

解決方案

1.使用互斥鎖(mutex key)

業(yè)界比較常用的做法,是使用mutex。簡(jiǎn)單地來(lái)說(shuō),就是在緩存失效的時(shí)候(判斷拿出來(lái)的值為空),不是立即去load db,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者M(jìn)emcache的ADD)去set一個(gè)mutex key,當(dāng)操作返回成功時(shí),再進(jìn)行l(wèi)oad db的操作并回設(shè)緩存;否則,就重試整個(gè)get緩存的方法。

SETNX,是「SET if Not eXists」的縮寫(xiě),也就是只有不存在的時(shí)候才設(shè)置,可以利用它來(lái)實(shí)現(xiàn)鎖的效果。在redis2.6.1之前版本未實(shí)現(xiàn)setnx的過(guò)期時(shí)間,所以這里給出兩種版本代碼參考:

//2.6.1前單機(jī)版本鎖 Stringget(Stringkey){ Stringvalue=redis.get(key); if(value==null){ if(redis.setnx(key_mutex,"1")){ //3mintimeouttoavoidmutexholdercrash redis.expire(key_mutex,3*60) value=db.get(key); redis.set(key,value); redis.delete(key_mutex); }else{ //其他線(xiàn)程休息50毫秒后重試 Thread.sleep(50); get(key); } } }

最新版本代碼:

publicStringget(key){ Stringvalue=redis.get(key); if(value==null){//代表緩存值過(guò)期 //設(shè)置3min的超時(shí),防止del操作失敗的時(shí)候,下次緩存過(guò)期一直不能loaddb if(redis.setnx(key_mutex,1,3*60)==1){//代表設(shè)置成功 value=db.get(key); redis.set(key,value,expire_secs); redis.del(key_mutex); }else{//這個(gè)時(shí)候代表同時(shí)候的其他線(xiàn)程已經(jīng)loaddb并回設(shè)到緩存了,這時(shí)候重試獲取緩存值即可 sleep(50); get(key);//重試 } }else{ returnvalue; } }

memcache代碼:

if(memcache.get(key)==null){ //3mintimeouttoavoidmutexholdercrash if(memcache.add(key_mutex,3*60*1000)==true){ value=db.get(key); memcache.set(key,value); memcache.delete(key_mutex); }else{ sleep(50); retry(); } }

2. "提前"使用互斥鎖(mutex key):

在value內(nèi)部設(shè)置1個(gè)超時(shí)值(timeout1), timeout1比實(shí)際的memcache timeout(timeout2)小。當(dāng)從cache讀取到timeout1發(fā)現(xiàn)它已經(jīng)過(guò)期時(shí)候,馬上延長(zhǎng)timeout1并重新設(shè)置到cache。然后再?gòu)臄?shù)據(jù)庫(kù)加載數(shù)據(jù)并設(shè)置到cache中。偽代碼如下:

v=memcache.get(key); if(v==null){ if(memcache.add(key_mutex,3*60*1000)==true){ value=db.get(key); memcache.set(key,value); memcache.delete(key_mutex); }else{ sleep(50); retry(); } }else{ if(v.timeout<=?now())?{?? ????????if?(memcache.add(key_mutex,?3?*?60?*?1000)?==?true)?{?? ????????????//?extend?the?timeout?for?other?threads?? ????????????v.timeout?+=?3?*?60?*?1000;?? ????????????memcache.set(key,?v,?KEY_TIMEOUT?*?2);?? ?? ????????????//?load?the?latest?value?from?db?? ????????????v?=?db.get(key);?? ????????????v.timeout?=?KEY_TIMEOUT;?? ????????????memcache.set(key,?value,?KEY_TIMEOUT?*?2);?? ????????????memcache.delete(key_mutex);?? ????????}?else?{?? ????????????sleep(50);?? ????????????retry();?? ????????}?? ????}?? }?

3. "永遠(yuǎn)不過(guò)期":

這里的“永遠(yuǎn)不過(guò)期”包含兩層意思:

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

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

從實(shí)戰(zhàn)看,這種方法對(duì)于性能非常友好,唯一不足的就是構(gòu)建緩存時(shí)候,其余線(xiàn)程(非構(gòu)建緩存的線(xiàn)程)可能訪(fǎng)問(wèn)的是老數(shù)據(jù),但是對(duì)于一般的互聯(lián)網(wǎng)功能來(lái)說(shuō)這個(gè)還是可以忍受。

Stringget(finalStringkey){ Vv=redis.get(key); Stringvalue=v.getValue(); longtimeout=v.getTimeout(); if(v.timeout<=?System.currentTimeMillis())?{?? ????????????//?異步更新后臺(tái)異常執(zhí)行?? ????????????threadPool.execute(new?Runnable()?{?? ????????????????public?void?run()?{?? ????????????????????String?keyMutex?=?"mutex:"?+?key;?? ????????????????????if?(redis.setnx(keyMutex,?"1"))?{?? ????????????????????????//?3?min?timeout?to?avoid?mutex?holder?crash?? ????????????????????????redis.expire(keyMutex,?3?*?60);?? ????????????????????????String?dbValue?=?db.get(key);?? ????????????????????????redis.set(key,?dbValue);?? ????????????????????????redis.delete(keyMutex);?? ????????????????????}?? ????????????????}?? ????????????});?? ????????}?? ????????return?value;?? }

4. 資源保護(hù):

采用netflix的hystrix,可以做資源的隔離保護(hù)主線(xiàn)程池,如果把這個(gè)應(yīng)用到緩存的構(gòu)建也未嘗不可。

沒(méi)有最佳只有最合適

解決方案 優(yōu)點(diǎn) 缺點(diǎn)
簡(jiǎn)單分布式互斥鎖(mutex key) 1. 思路簡(jiǎn)單
2. 保證一致性
1. 代碼復(fù)雜度增大
2. 存在死鎖的風(fēng)險(xiǎn)
3. 存在線(xiàn)程池阻塞的風(fēng)險(xiǎn)
“提前”使用互斥鎖 1. 保證一致性 同上
不過(guò)期(本文) 1. 異步構(gòu)建緩存,不會(huì)阻塞線(xiàn)程池 1. 不保證一致性。
2. 代碼復(fù)雜度增大(每個(gè)value都要維護(hù)一個(gè)timekey)。
3. 占用一定的內(nèi)存空間(每個(gè)value都要維護(hù)一個(gè)timekey)。
資源隔離組件hystrix(本文) 1. hystrix技術(shù)成熟,有效保證后端。
2. hystrix監(jiān)控強(qiáng)大。
1. 部分訪(fǎng)問(wèn)存在降級(jí)策略。

四種方案來(lái)源網(wǎng)絡(luò),詳文鏈接:http://carlosfu.iteye.com/blog/2269687

總結(jié)

針對(duì)業(yè)務(wù)系統(tǒng),永遠(yuǎn)都是具體情況具體分析,沒(méi)有最好,只有最合適。

最后,對(duì)于緩存系統(tǒng)常見(jiàn)的緩存滿(mǎn)了和數(shù)據(jù)丟失問(wèn)題,需要根據(jù)具體業(yè)務(wù)分析,通常我們采用LRU策略處理溢出,Redis的RDB和AOF持久化策略來(lái)保證一定情況下的數(shù)據(jù)安全。

原文標(biāo)題:如何設(shè)計(jì)緩存系統(tǒng):緩存穿透,緩存擊穿,緩存雪崩解決方案分析

文章出處:【微信公眾號(hào):數(shù)據(jù)分析與開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 存儲(chǔ)
    +關(guān)注

    關(guān)注

    13

    文章

    4786

    瀏覽量

    90054
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    248

    瀏覽量

    27758

原文標(biāo)題:如何設(shè)計(jì)緩存系統(tǒng):緩存穿透,緩存擊穿,緩存雪崩解決方案分析

文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    C語(yǔ)言的緩沖區(qū)(緩存)詳解

    緩沖區(qū)又稱(chēng)為緩存,它是內(nèi)存空間的部分。也就是說(shuō),在內(nèi)存空間中預(yù)留了定的存儲(chǔ)空間,這些存儲(chǔ)空間用來(lái)緩沖輸入或輸出的數(shù)據(jù),這部分預(yù)留的空間就叫做緩沖區(qū)。   緩沖區(qū)根據(jù)其對(duì)應(yīng)的是輸入設(shè)備還是輸出設(shè)備
    發(fā)表于 01-14 07:30

    ESP32 編譯過(guò)程中 bootloader 配置階段的 CMake 緩存沖突錯(cuò)誤,記錄

    你遇到的是 ESP32 編譯過(guò)程中 bootloader 配置階段的 CMake 緩存沖突錯(cuò)誤,核心原因是系統(tǒng)中混合了 ESP-IDF v5.5.1 和 v5.4.3 兩個(gè)版本的路徑,導(dǎo)致
    發(fā)表于 12-23 07:07

    串口DMA發(fā)送有緩存嗎?

    串口DMA發(fā)送有緩存嗎, 我是從ringbuffer取出來(lái),放到申請(qǐng)的緩存里,啟動(dòng)串口DMA發(fā)送,然后就釋放了。暫時(shí)沒(méi)發(fā)現(xiàn)什么問(wèn)題。 用的drv_usart.c是這個(gè)版本
    發(fā)表于 10-10 06:14

    Redis緩存的經(jīng)典問(wèn)題和解決方案

    用戶(hù)瘋狂查詢(xún)數(shù)據(jù)庫(kù)中不存在的數(shù)據(jù),每次查詢(xún)都繞過(guò)緩存直接打到數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)壓力驟增。
    的頭像 發(fā)表于 08-20 16:24 ?773次閱讀

    緩存之美:萬(wàn)文詳解 Caffeine 實(shí)現(xiàn)原理(上)

    文章將采用“總-分-總”的結(jié)構(gòu)對(duì)配置固定大小元素驅(qū)逐策略的 Caffeine 緩存進(jìn)行介紹,首先會(huì)講解它的實(shí)現(xiàn)原理,在大家對(duì)它有個(gè)概念之后再深入具體源碼的細(xì)節(jié)之中,理解它的設(shè)計(jì)理念,從中能學(xué)習(xí)到
    的頭像 發(fā)表于 08-05 14:49 ?700次閱讀
    <b class='flag-5'>緩存</b>之美:萬(wàn)文詳解 Caffeine 實(shí)現(xiàn)原理(上)

    本地緩存 Caffeine 中的時(shí)間輪(TimeWheel)是什么?

    我們?cè)敿?xì)介紹了 Caffeine 緩存添加元素和讀取元素的流程,并詳細(xì)解析了配置固定元素?cái)?shù)量驅(qū)逐策略的實(shí)現(xiàn)原理。在本文中我們將主要介紹 配置元素過(guò)期時(shí)間策略的實(shí)現(xiàn)原理 ,補(bǔ)全 Caffeine
    的頭像 發(fā)表于 08-05 14:48 ?609次閱讀
    本地<b class='flag-5'>緩存</b> Caffeine 中的時(shí)間輪(TimeWheel)是什么?

    harmony-utils之CacheUtil,緩存工具類(lèi)

    harmony-utils之CacheUtil,緩存工具類(lèi)
    的頭像 發(fā)表于 07-04 16:36 ?492次閱讀

    高性能緩存設(shè)計(jì):如何解決緩存偽共享問(wèn)題

    在多核高并發(fā)場(chǎng)景下, 緩存偽共享(False Sharing) 是導(dǎo)致性能驟降的“隱形殺手”。當(dāng)不同線(xiàn)程頻繁修改同緩存行(Cache Line)中的獨(dú)立變量時(shí),CPU緩存
    的頭像 發(fā)表于 07-01 15:01 ?759次閱讀
    高性能<b class='flag-5'>緩存</b>設(shè)計(jì):如何解決<b class='flag-5'>緩存</b>偽共享問(wèn)題

    請(qǐng)問(wèn)如何增大usb3.0從設(shè)備fifo接口固件中的寫(xiě)dma緩存大???

    現(xiàn)有的固件是默認(rèn)的,分別配置了2個(gè)1KB的緩存給讀和寫(xiě)的dma。我想要多分配點(diǎn)緩存給寫(xiě)dma,比如分配4kB給寫(xiě)dma。請(qǐng)教下該如何修改
    發(fā)表于 05-14 08:13

    cyusb3014 slave fifo模式In和Out緩存大小不樣時(shí),顯示錯(cuò)誤怎么解決?

    cyusb3014 slave fifo 模式 In 和 Out 緩存大小設(shè)置不樣時(shí)(比如:U2P DMA緩存16K,P2U DMA緩存1K),可以測(cè)出來(lái)實(shí)際就是設(shè)置值,但在USB
    發(fā)表于 05-13 06:55

    MCU緩存設(shè)計(jì)

    MCU 設(shè)計(jì)通過(guò)優(yōu)化指令與數(shù)據(jù)的訪(fǎng)問(wèn)效率,顯著提升系統(tǒng)性能并降低功耗,其核心架構(gòu)與實(shí)現(xiàn)策略如下: 緩存類(lèi)型與結(jié)構(gòu) 指令緩存(I-Cache)與數(shù)據(jù)
    的頭像 發(fā)表于 05-07 15:29 ?1107次閱讀

    Nginx緩存配置詳解

    Nginx 是個(gè)功能強(qiáng)大的 Web 服務(wù)器和反向代理服務(wù)器,它可以用于實(shí)現(xiàn)靜態(tài)內(nèi)容的緩存,緩存可以分為客戶(hù)端緩存和服務(wù)端
    的頭像 發(fā)表于 05-07 14:03 ?1245次閱讀
    Nginx<b class='flag-5'>緩存</b>配置詳解

    高速SSD存儲(chǔ)系統(tǒng)中數(shù)據(jù)緩存控制器整體頂層設(shè)計(jì)

    數(shù)據(jù)緩存控制器主要實(shí)現(xiàn)了對(duì)大量突發(fā)數(shù)據(jù)的緩存、AXI4接口與AXI4-Stream接口之間的轉(zhuǎn)換和NVMe命令的生成等功能。這里主要介紹相關(guān)開(kāi)發(fā)流程。
    的頭像 發(fā)表于 04-14 10:46 ?777次閱讀
    高速SSD存儲(chǔ)<b class='flag-5'>系統(tǒng)</b>中數(shù)據(jù)<b class='flag-5'>緩存</b>控制器整體頂層設(shè)計(jì)

    nginx中強(qiáng)緩存和協(xié)商緩存介紹

    強(qiáng)緩存直接告訴瀏覽器:在緩存過(guò)期前,無(wú)需與服務(wù)器通信,直接使用本地緩存。
    的頭像 發(fā)表于 04-01 16:01 ?972次閱讀

    MPC5777C如何在禁用其余數(shù)據(jù)緩存的同時(shí)繼續(xù)保持堆棧工作?

    我按照 AN5191指南啟動(dòng)MPC5777C自定義板,它的些內(nèi)置測(cè)試要求我禁用緩存以執(zhí)行某些作,然后重新啟用它們以進(jìn)行正常作??紤]到我把半的數(shù)據(jù)緩存作為我的堆棧(使用基于 dcbz
    發(fā)表于 03-27 06:01