Redis技術(shù)專(zhuān)題之緩存擊穿娱挨、緩存雪崩余指、緩存穿透

? ? ? ?當(dāng)我們使用一項(xiàng)技術(shù)時(shí),我們就需要對(duì)它有一定的了解,知道我們?yōu)槭裁匆ナ褂盟途担軌蚍治鍪褂眠@項(xiàng)技術(shù)所帶來(lái)的的回報(bào)以及我們所需要付出的代價(jià)碉碉。

緩存所帶來(lái)的收益:

??高速讀寫(xiě):緩存會(huì)加速讀寫(xiě)速度,利用CPU L1/L2/L3 Cache淮韭、Linux page Cache加速硬盤(pán)讀寫(xiě)垢粮、瀏覽器緩存、Ehcache緩存緩存數(shù)據(jù)靠粪,其性能都會(huì)比關(guān)系型數(shù)據(jù)庫(kù)高很多蜡吧,內(nèi)存級(jí)別的讀寫(xiě)性能大大優(yōu)于磁盤(pán)級(jí)別的讀寫(xiě)性能。

? ? ? ?降低后端負(fù)載:后端服務(wù)器業(yè)務(wù)通過(guò)使用Redis減少對(duì)MySQL的請(qǐng)求訪問(wèn)占键,降低MySQL負(fù)載等昔善。

緩存所帶來(lái)的代價(jià):

? ? ? ?數(shù)據(jù)不一致:緩存層和數(shù)據(jù)庫(kù)層面數(shù)據(jù)不一致,例如Redis已經(jīng)對(duì)某條復(fù)雜的數(shù)據(jù)進(jìn)行緩存畔乙,此時(shí)通過(guò)后臺(tái)修改該數(shù)據(jù)君仆,由于大部分情況下我們不會(huì)主動(dòng)對(duì)Redis進(jìn)行數(shù)據(jù)刪除,因?yàn)閺男阅芤约鞍菪詠?lái)說(shuō)都不需要進(jìn)行刪除操作牲距,所以就導(dǎo)致緩存數(shù)據(jù)同步不及時(shí)返咱,這些都和我們自身應(yīng)用更新策略有關(guān),需要根據(jù)實(shí)際情況合理設(shè)置數(shù)據(jù)緩存過(guò)期時(shí)間等相關(guān)操作牍鞠。

代碼維護(hù)成本(人工成本):不適用Redis緩存的情況下咖摹,我們只需讀寫(xiě)MySQL就能實(shí)現(xiàn)功能,但當(dāng)我們加入緩存之后就需要去維護(hù)緩存數(shù)據(jù)的處理邏輯难述,增加了代碼復(fù)雜度萤晴。某些情況下會(huì)降低項(xiàng)目開(kāi)發(fā)以及測(cè)試效率,例如測(cè)試人員需要測(cè)試有緩存時(shí)的情況龄广,也要測(cè)試沒(méi)有緩存時(shí)的情況硫眯,另外當(dāng)測(cè)試人員測(cè)試功能無(wú)需關(guān)注緩存時(shí)需手動(dòng)清除對(duì)應(yīng)緩存蕴侧,否則需要等待數(shù)據(jù)緩存過(guò)期择同,延長(zhǎng)測(cè)試時(shí)間。

? ? ? ? ?性能風(fēng)險(xiǎn):堆內(nèi)緩存由于是存儲(chǔ)在本地服務(wù)器中净宵,由JVM或者本地服務(wù)器來(lái)維護(hù)數(shù)據(jù)敲才,可能帶來(lái)內(nèi)存溢出的風(fēng)險(xiǎn)甚至影響用戶進(jìn)程,如ehCache择葡、loadingCache紧武。

?????堆內(nèi)緩存和遠(yuǎn)程服務(wù)器緩存如何選擇?對(duì)于這個(gè)問(wèn)題主要考慮以下幾點(diǎn):

堆內(nèi)緩存一般性能更好敏储,遠(yuǎn)程緩存需要套接字傳輸阻星。

????????用戶級(jí)別緩存盡量采用遠(yuǎn)程緩存(例如集群架構(gòu)下,多臺(tái)機(jī)器會(huì)重復(fù)緩存同一組數(shù)據(jù))。

????????大數(shù)據(jù)量盡量采用遠(yuǎn)程緩存妥箕,避免造成應(yīng)用服務(wù)器壓力過(guò)大滥酥,遵循服務(wù)節(jié)點(diǎn)化原則。

2.緩存穿透

??在我們使用Redis的過(guò)程中畦幢,Redis的確幫助我們解決了很多的問(wèn)題坎吻,但是當(dāng)技術(shù)和業(yè)務(wù)結(jié)合在一起時(shí)就會(huì)發(fā)現(xiàn)一些讓人深思的問(wèn)題。緩存穿透就是其中一個(gè)宇葱。

2.1 什么是緩存穿透瘦真?

?? ?上面這張圖是我們正常業(yè)務(wù)場(chǎng)景下的一個(gè)流程(客戶端->服務(wù)端[Redis->DB]),那么緩存穿透指的是當(dāng)用戶查詢(xún)數(shù)據(jù)黍瞧,再緩存中不存在诸尽,并且在數(shù)據(jù)庫(kù)也不存在時(shí),導(dǎo)致用戶查詢(xún)這樣的數(shù)據(jù)(或者惡意攻擊) 在緩存中找不到對(duì)應(yīng)key的value雷逆,每次都需要要在數(shù)據(jù)庫(kù)中查詢(xún)一遍弦讽,然后返回空值。其實(shí)這就相當(dāng)于進(jìn)行了兩次無(wú)用的查詢(xún)膀哲,這樣請(qǐng)求就繞過(guò)緩存直接查數(shù)據(jù)庫(kù)往产,對(duì)數(shù)據(jù)庫(kù)造成了很大的壓力。

2.2 如何防止緩存穿透某宪?

?? ? ? 說(shuō)到如何防止緩存穿透仿村,這里我主要提出兩點(diǎn)建議:

緩存空值:如果DB查詢(xún)返回?cái)?shù)據(jù)或者業(yè)務(wù)結(jié)果為空,此時(shí)我們?nèi)匀粚⒖战Y(jié)果進(jìn)行緩存兴喂,設(shè)置較短的過(guò)期時(shí)間(不超過(guò)五分鐘)蔼囊。

? ? ? ?采用布隆過(guò)濾器BloomFilter:事先將所有可能存在的數(shù)據(jù)哈希后放入到一個(gè)足夠大的BitMap中,若一個(gè)數(shù)據(jù)一定不存在則會(huì)被攔截掉衣迷,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢(xún)壓力畏鼓。關(guān)于布隆過(guò)濾器后面會(huì)寫(xiě)一篇博客對(duì)其進(jìn)行詳細(xì)介紹。

3.緩存雪崩

3.1 什么是緩存雪崩壶谒?

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

3.2 如何防止緩存雪崩菌瘪?

?? ? 這里我們看看如何防止緩存雪崩:

? ? ? 加鎖排隊(duì):維護(hù)一個(gè)mutex互斥鎖腮敌,通過(guò)Redis的SETNX命令去設(shè)置一把當(dāng)前業(yè)務(wù)操作的鎖(例如setnx lock_uid_001 value nullValue、setnx lock_white_list value nullValue),當(dāng)操作成功時(shí)糜工,再進(jìn)行LoadDB操作回設(shè)緩存斗这,否則重試get緩存。

數(shù)據(jù)預(yù)熱:緩存預(yù)熱就是當(dāng)我們新部署一個(gè)項(xiàng)目系統(tǒng)時(shí)啤斗,將相關(guān)緩存數(shù)據(jù)直接加載到緩存中表箭。這樣可以避免在用戶請(qǐng)求時(shí)候,再去查詢(xún)數(shù)據(jù)庫(kù)放入緩存钮莲。用戶可以直接查詢(xún)事先被預(yù)熱的緩存數(shù)據(jù)免钻,可以預(yù)熱大并發(fā)量、熱度高的Key緩存數(shù)據(jù)崔拥。

? ? ? ?雙層緩存策略:同一條數(shù)據(jù)我們可以維護(hù)兩套緩存极舔,C1為原始緩存,C2為拷貝緩存链瓦,當(dāng)C1失效時(shí)拆魏,可以讀取C2,都不存在時(shí)再去訪問(wèn)數(shù)據(jù)庫(kù)回設(shè)慈俯,當(dāng)然C1緩存失效時(shí)間需要設(shè)置為短期渤刃,而C2設(shè)置為長(zhǎng)期。這種方式最大缺點(diǎn)就是占用的內(nèi)存翻倍贴膘。

? ? ? ?定時(shí)更新緩存策略:對(duì)于失效性要求低的緩存卖子,可以在容器啟動(dòng)初始化時(shí)加載放入緩存,采用定時(shí)任務(wù)更新或移除緩存刑峡。

? ? ? ?時(shí)間浮動(dòng)策略:設(shè)置不同過(guò)期時(shí)間洋闽,讓緩存失效的時(shí)間點(diǎn)盡量均勻,避免集中失效

穿透

?穿透:頻繁查詢(xún)一個(gè)不存在的數(shù)據(jù)突梦,由于緩存不命中诫舅,每次都要查詢(xún)持久層。從而失去緩存的意義宫患。

解決辦法:

? ? 1.用一個(gè)bitmap和n個(gè)hash函數(shù)做布隆過(guò)濾器過(guò)濾沒(méi)有在緩存的鍵刊懈。

?解釋?zhuān)簩?shù)據(jù)庫(kù)的id根據(jù)n個(gè)hash函數(shù)存儲(chǔ)到對(duì)應(yīng)的bitmap二進(jìn)制數(shù)組里面,然后通過(guò)修改為1的標(biāo)志來(lái)進(jìn)而判斷位置是否相同來(lái)確定是否存在對(duì)應(yīng)的key在此redis里面撮奏,從而達(dá)到了減少掃描redis內(nèi)存數(shù)據(jù)的方案俏讹。(確定無(wú)法一定不存在的key)当宴。

? ? 2.持久層查詢(xún)不到就緩存空結(jié)果畜吊,有效時(shí)間為數(shù)分鐘。(存儲(chǔ)空結(jié)果)户矢,防止大量查詢(xún)DB

雪崩

????雪崩:緩存大量失效的時(shí)候玲献,引發(fā)大量查詢(xún)數(shù)據(jù)庫(kù)。

解決辦法:

? ? 1.用鎖/分布式鎖或者隊(duì)列串行訪問(wèn)

? ? 2.緩存失效時(shí)間均勻分布

????3.緩存預(yù)熱,在啟動(dòng)或者初始化 加載一些緩存數(shù)據(jù)進(jìn)入捌年,防止大量去查詢(xún)?cè)L問(wèn)DB

? ? 4.二級(jí)雙層緩存機(jī)制瓢娜,當(dāng)一級(jí)失效則去訪問(wèn)二級(jí)遠(yuǎn)程的MemoryCache機(jī)制。

熱點(diǎn)key

? ? 熱點(diǎn)key:某個(gè)key訪問(wèn)非常頻繁礼预,當(dāng)key失效的時(shí)候有大量線程來(lái)構(gòu)建緩存眠砾,導(dǎo)致負(fù)載增加,系統(tǒng)崩潰托酸。

解決辦法:

① 使用鎖褒颈,單機(jī)用synchronized,lock等,分布式用分布式鎖励堡。

② 緩存過(guò)期時(shí)間不設(shè)置谷丸,而是設(shè)置在key對(duì)應(yīng)的value里。如果檢測(cè)到存的時(shí)間超過(guò)過(guò)期時(shí)間則異步更新緩存应结。

③ 在value設(shè)置一個(gè)比過(guò)期時(shí)間t0小的過(guò)期時(shí)間值t1刨疼,當(dāng)t1過(guò)期的時(shí)候,延長(zhǎng)t1并做更新緩存操作鹅龄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末揩慕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子扮休,更是在濱河造成了極大的恐慌漩绵,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肛炮,死亡現(xiàn)場(chǎng)離奇詭異止吐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)侨糟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)碍扔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人秕重,你說(shuō)我怎么就攤上這事不同。” “怎么了溶耘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵二拐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我凳兵,道長(zhǎng)百新,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任庐扫,我火速辦了婚禮饭望,結(jié)果婚禮上仗哨,老公的妹妹穿的比我還像新娘。我一直安慰自己铅辞,他們只是感情好厌漂,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著斟珊,像睡著了一般苇倡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上囤踩,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天雏节,我揣著相機(jī)與錄音,去河邊找鬼高职。 笑死钩乍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怔锌。 我是一名探鬼主播寥粹,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼埃元!你這毒婦竟也來(lái)了涝涤?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤岛杀,失蹤者是張志新(化名)和其女友劉穎阔拳,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體类嗤,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡糊肠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了遗锣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片货裹。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖精偿,靈堂內(nèi)的尸體忽然破棺而出弧圆,到底是詐尸還是另有隱情,我是刑警寧澤笔咽,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布搔预,位于F島的核電站,受9級(jí)特大地震影響叶组,放射性物質(zhì)發(fā)生泄漏拯田。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一扶叉、第九天 我趴在偏房一處隱蔽的房頂上張望勿锅。 院中可真熱鬧,春花似錦枣氧、人聲如沸溢十。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)张弛。三九已至,卻和暖如春酪劫,著一層夾襖步出監(jiān)牢的瞬間吞鸭,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工覆糟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刻剥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓滩字,卻偏偏與公主長(zhǎng)得像造虏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子麦箍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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

  • 寫(xiě)在前 在看redis緩存雪崩、擊穿和穿透之前诀蓉,先回答一下幾個(gè)緩存的問(wèn)題栗竖。 為什么要用 redis 而不用 map...
    _code_x閱讀 1,001評(píng)論 0 2
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭渠啤,有人歡樂(lè)有人憂愁划滋,有人驚喜有人失落,有的覺(jué)得收獲滿滿有...
    陌忘宇閱讀 8,547評(píng)論 28 53
  • 信任包括信任自己和信任他人 很多時(shí)候埃篓,很多事情处坪,失敗、遺憾架专、錯(cuò)過(guò)同窘,源于不自信,不信任他人 覺(jué)得自己做不成部脚,別人做不...
    吳氵晃閱讀 6,195評(píng)論 4 8
  • 步驟:發(fā)微博01-導(dǎo)航欄內(nèi)容 -> 發(fā)微博02-自定義TextView -> 發(fā)微博03-完善TextView和...
    dibadalu閱讀 3,142評(píng)論 1 3
  • 雜志上說(shuō)生理期的時(shí)候免疫力會(huì)下降委刘,我覺(jué)得挺玄乎丧没,但每次都應(yīng)驗(yàn)在我身上鹰椒,那幾天總是會(huì)感冒,所以生理期同時(shí)會(huì)伴隨著...
    宿原小姐閱讀 1,089評(píng)論 1 3