Redis - 緩存穿透叁温、擊穿、雪崩

溫馨提示:面試常問(wèn)核畴,多需結(jié)合項(xiàng)目實(shí)戰(zhàn)經(jīng)驗(yàn)

一膝但、緩存穿透

緩存穿透是指緩存和數(shù)據(jù)庫(kù)中都沒(méi)有的數(shù)據(jù),而用戶不斷發(fā)起請(qǐng)求谤草,如發(fā)起id為-1的數(shù)據(jù)或者特別大的不存在的數(shù)據(jù)跟束。有可能是黑客利用漏洞攻擊從而去壓垮應(yīng)用的數(shù)據(jù)庫(kù)。

常見(jiàn)解決方案

對(duì)于緩存穿透問(wèn)題丑孩,常見(jiàn)的解決方案有以下三種:

  • 驗(yàn)證攔截:接口層進(jìn)行校驗(yàn)冀宴,如鑒定用戶權(quán)限,對(duì)ID之類的字段做基礎(chǔ)的校驗(yàn)温学,如id<=0的字段直接攔截略贮;
  • 緩存空數(shù)據(jù):當(dāng)數(shù)據(jù)庫(kù)查詢到的數(shù)據(jù)為空時(shí),也將這條數(shù)據(jù)進(jìn)行緩存仗岖,但緩存的有效性設(shè)置得要較短逃延,以免影響正常數(shù)據(jù)的緩存;
Copypublic Student getStudentsByID(Long id) {
    // 從Redis中獲取學(xué)生信息
    Student student = redisTemplate.opsForValue()
        .get(String.valueOf(id));
    if (student != null) {
        return student;
    }
    // 從數(shù)據(jù)庫(kù)查詢學(xué)生信息轧拄,并存入Redis
    student = studentDao.selectByStudentId(id);
    if (student != null) {
        redisTemplate.opsForValue()
            .set(String.valueOf(id), student, 60, TimeUnit.MINUTES);
    } else {
        // 即使不存在揽祥,也將其存入緩存中
        redisTemplate.opsForValue()
            .set(String.valueOf(id), null, 60, TimeUnit.SECONDS);
    }
    return student;
}
  • 使用布隆過(guò)濾器:布隆過(guò)濾器是一種比較獨(dú)特?cái)?shù)據(jù)結(jié)構(gòu),有一定的誤差紧帕。當(dāng)它指定一個(gè)數(shù)據(jù)存在時(shí)盔然,它不一定存在,但是當(dāng)它指定一個(gè)數(shù)據(jù)不存在時(shí)是嗜,那么它一定是不存在的愈案。

2. 布隆過(guò)濾器

  • 布隆過(guò)濾器是一種比較特殊的數(shù)據(jù)結(jié)構(gòu),有點(diǎn)類似與HashMap鹅搪,在業(yè)務(wù)中我們可能會(huì)通過(guò)使用HashMap來(lái)判斷一個(gè)值是否存在站绪,它可以在O(1)時(shí)間復(fù)雜度內(nèi)返回結(jié)果,效率極高丽柿,但是受限于存儲(chǔ)容量恢准,如果可能需要去判斷的值超過(guò)億級(jí)別,那么HashMap所占的內(nèi)存就很可觀了甫题。
  • BloomFilter解決這個(gè)問(wèn)題的方案很簡(jiǎn)單馁筐。首先用多個(gè)bit位去代替HashMap中的數(shù)組,這樣的話儲(chǔ)存空間就下來(lái)了坠非,之后就是對(duì) Key 進(jìn)行多次哈希敏沉,將 Key 哈希后的值所對(duì)應(yīng)的 bit 位置為1。
  • 當(dāng)判斷一個(gè)元素是否存在時(shí),就去判斷這個(gè)值哈希出來(lái)的比特位是否都為1盟迟,如果都為1秋泳,那么可能存在,也可能不存在(如下圖F)攒菠。但是如果有一個(gè)bit位不為1迫皱,那么這個(gè)Key就肯定不存在。

注意:BloomFilter并不支持刪除操作辖众,只支持添加操作卓起。這一點(diǎn)很容易理解,因?yàn)槟闳绻獎(jiǎng)h除數(shù)據(jù)赵辕,就得將對(duì)應(yīng)的bit位置為0既绩,但是你這個(gè)Key對(duì)應(yīng)的bit位可能其他的Key也對(duì)應(yīng)著。

緩存空數(shù)據(jù)與布隆過(guò)濾器的比較

上面對(duì)這兩種方案都進(jìn)行了簡(jiǎn)單的介紹还惠,緩存空數(shù)據(jù)與布隆過(guò)濾器都能有效解決緩存穿透問(wèn)題,但使用場(chǎng)景有著些許不同私杜;

  • 當(dāng)一些惡意攻擊查詢查詢的key各不相同蚕键,而且數(shù)量巨多拇砰,此時(shí)緩存空數(shù)據(jù)不是一個(gè)好的解決方案进萄。因?yàn)樗枰鎯?chǔ)所有的Key杀餐,內(nèi)存空間占用高拟逮。并且在這種情況下赵颅,很多key可能只用一次慈格,所以存儲(chǔ)下來(lái)沒(méi)有意義芬首。所以對(duì)于這種情況而言畴博,使用布隆過(guò)濾器是個(gè)不錯(cuò)的選擇瓢捉;
  • 而對(duì)與空數(shù)據(jù)的Key數(shù)量有限频丘、Key重復(fù)請(qǐng)求效率較高的場(chǎng)景而言,可以選擇緩存空數(shù)據(jù)的方案泡态。

二搂漠、緩存擊穿

緩存擊穿是指當(dāng)前熱點(diǎn)數(shù)據(jù)存儲(chǔ)到期時(shí),多個(gè)線程同時(shí)并發(fā)訪問(wèn)熱點(diǎn)數(shù)據(jù)某弦。因?yàn)榫彺鎰傔^(guò)期桐汤,所有并發(fā)請(qǐng)求都會(huì)到數(shù)據(jù)庫(kù)中查詢數(shù)據(jù)。

解決方案

  • 將熱點(diǎn)數(shù)據(jù)設(shè)置為永不過(guò)期靶壮;

  • 加互斥鎖:互斥鎖可以控制查詢數(shù)據(jù)庫(kù)的線程訪問(wèn)怔毛,但這種方案會(huì)導(dǎo)致系統(tǒng)的吞吐量下降,需要根據(jù)實(shí)際情況使用腾降。

Copypublic String get(key) {
    String value = redis.get(key);
    if (value == null) { // 代表緩存值過(guò)期
        // 設(shè)置3min的超時(shí)拣度,防止del操作失敗的時(shí)候,下次緩存過(guò)期一直不能load db
        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í)候的其他線程已經(jīng)load db并回設(shè)到緩存了,這時(shí)候重試獲取緩存值即可
            sleep(50);
            get(key);  // 重試
        }
    } else {
        return value;
    }
}

三蜡娶、緩存雪崩

緩存雪崩發(fā)生有幾種情況混卵,比如大量緩存集中在或者緩存同時(shí)在大范圍中失效,出現(xiàn)了大量請(qǐng)求去訪問(wèn)數(shù)據(jù)庫(kù)窖张,從而導(dǎo)致CPU和內(nèi)存過(guò)載幕随,甚至停機(jī)。

一個(gè)簡(jiǎn)單的雪崩過(guò)程:

  1. Redis 集群產(chǎn)生了大面積故障宿接;
  2. 緩存失敗赘淮,此時(shí)仍有大量請(qǐng)求去訪問(wèn) Redis 緩存服務(wù)器;
  3. 在大量 Redis 請(qǐng)求失敗后睦霎,這些請(qǐng)求將會(huì)去訪問(wèn)數(shù)據(jù)庫(kù)梢卸;
  4. 由于應(yīng)用的設(shè)計(jì)依賴于數(shù)據(jù)庫(kù)和 Redis 服務(wù),很快就會(huì)造成服務(wù)器集群的雪崩副女,最終導(dǎo)致整個(gè)系統(tǒng)的癱瘓蛤高。

解決方案

  • 【事前】高可用緩存:高可用緩存是防止出現(xiàn)整個(gè)緩存故障。即使個(gè)別節(jié)點(diǎn)碑幅,機(jī)器甚至機(jī)房都關(guān)閉戴陡,系統(tǒng)仍然可以提供服務(wù),Redis 哨兵(Sentinel) 和 Redis 集群(Cluster) 都可以做到高可用沟涨;
  • 【事中】緩存降級(jí)(臨時(shí)支持):當(dāng)訪問(wèn)次數(shù)急劇增加導(dǎo)致服務(wù)出現(xiàn)問(wèn)題時(shí)恤批,我們?nèi)绾未_保服務(wù)仍然可用。在國(guó)內(nèi)使用比較多的是 Hystrix裹赴,它通過(guò)熔斷喜庞、降級(jí)、限流三個(gè)手段來(lái)降低雪崩發(fā)生后的損失棋返。只要確保數(shù)據(jù)庫(kù)不死延都,系統(tǒng)總可以響應(yīng)請(qǐng)求,每年的春節(jié) 12306 我們不都是這么過(guò)來(lái)的嗎懊昨?只要還可以響應(yīng)起碼還有搶到票的機(jī)會(huì)窄潭;
  • 【事后】Redis備份和快速預(yù)熱:Redis數(shù)據(jù)備份和恢復(fù)、快速緩存預(yù)熱酵颁。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嫉你,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子躏惋,更是在濱河造成了極大的恐慌幽污,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件簿姨,死亡現(xiàn)場(chǎng)離奇詭異距误,居然都是意外死亡簸搞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門准潭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)趁俊,“玉大人,你說(shuō)我怎么就攤上這事刑然∷吕蓿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵泼掠,是天一觀的道長(zhǎng)怔软。 經(jīng)常有香客問(wèn)我,道長(zhǎng)择镇,這世上最難降的妖魔是什么挡逼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮腻豌,結(jié)果婚禮上家坎,老公的妹妹穿的比我還像新娘。我一直安慰自己饲梭,他們只是感情好乘盖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著憔涉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪析苫。 梳的紋絲不亂的頭發(fā)上兜叨,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音衩侥,去河邊找鬼国旷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛茫死,可吹牛的內(nèi)容都是我干的跪但。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼峦萎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼屡久!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起爱榔,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤被环,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后详幽,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體筛欢,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡浸锨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了版姑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柱搜。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖剥险,靈堂內(nèi)的尸體忽然破棺而出聪蘸,到底是詐尸還是另有隱情,我是刑警寧澤炒嘲,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布宇姚,位于F島的核電站,受9級(jí)特大地震影響夫凸,放射性物質(zhì)發(fā)生泄漏浑劳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一夭拌、第九天 我趴在偏房一處隱蔽的房頂上張望魔熏。 院中可真熱鬧,春花似錦鸽扁、人聲如沸蒜绽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)躲雅。三九已至,卻和暖如春骡和,著一層夾襖步出監(jiān)牢的瞬間相赁,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工慰于, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钮科,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓婆赠,卻偏偏與公主長(zhǎng)得像绵脯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子休里,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容