溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java緩存設(shè)計(jì)要考慮哪些問題

發(fā)布時(shí)間:2022-01-17 10:11:02 來源:億速云 閱讀:161 作者:iii 欄目:軟件技術(shù)

本篇內(nèi)容主要講解“Java緩存設(shè)計(jì)要考慮哪些問題”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java緩存設(shè)計(jì)要考慮哪些問題”吧!

  緩存穿透

  緩存穿透是指查詢一個(gè)一定不存在的數(shù)據(jù),因?yàn)檫@個(gè)數(shù)據(jù)不存在,所以永遠(yuǎn)不會(huì)被緩存,所以每次請求都會(huì)去請求數(shù)據(jù)庫。

  例如我們請求一個(gè) UserID 為 -1 的用戶數(shù)據(jù),因?yàn)樵撚脩舨淮嬖?,所以該請求每次都?huì)去讀取數(shù)據(jù)庫。在這種情況下,如果某些心懷不軌的人利用這個(gè)存在的漏洞去偽造大量的請求,那么很可能導(dǎo)致DB承受不了那么大的流量就掛掉了。

  對于緩存穿透,有幾種解決方案,一種是事前預(yù)防,一種是事后預(yù)防。

  事前預(yù)防。其實(shí)就是對所有請求都進(jìn)行參數(shù)校驗(yàn),把絕大多數(shù)非法的請求抵擋在最外層。在我們舉的這個(gè)例子中,那么就是做參數(shù)校驗(yàn),對于 UserID 小于 0 的請求全部拒絕。但即使我們做了全面的參數(shù)校驗(yàn),還是可能存在漏網(wǎng)之魚,會(huì)出現(xiàn)一些我們沒想到的情況。

  例如我們的 UserID 是遞增的,那么如果有人請求一個(gè) UserID 很大的用戶信息(例如:1000000),而我們的 UserID 最大也就 10000。這個(gè)時(shí)候,你不可能限制 UserID 大于 1 萬的就是非法的,或者說大于 10 萬就是非法的,所以該用戶ID肯定可以通過參數(shù)校驗(yàn)。但該用戶確實(shí)不存在,所以每次請求都會(huì)去請求數(shù)據(jù)庫。

  其實(shí)上面只是我所能想到的一種情況,我們沒想到的情況肯定還有很多。對于這些情況,我們能做的就是時(shí)候預(yù)防。

  事后預(yù)防。事后預(yù)防說的就是當(dāng)查詢到一個(gè)空的結(jié)果時(shí),我們?nèi)匀粚⑦@個(gè)空的結(jié)果進(jìn)行緩存,但是設(shè)置一個(gè)很短的過期時(shí)間(例如一分鐘)。在這里我們可以看到,其實(shí)我們并沒有完全預(yù)防非法請求,只不過是將非法請求的風(fēng)險(xiǎn)讓承受能力更強(qiáng)的redis去承擔(dān),讓承受能力稍弱的數(shù)據(jù)庫更安全。

  通過上面這兩種處理方式,我們基本可以解決緩存穿透的問題。事前預(yù)防解決80%的非法請求,剩下的20%非法請求則使用Redis轉(zhuǎn)移風(fēng)險(xiǎn)。

  緩存擊穿

  如果你的應(yīng)用中有一些訪問量很高的熱點(diǎn)數(shù)據(jù),我們一般會(huì)將其放在緩存中以提高訪問速度。另外,為了保持時(shí)效性,我們通常還會(huì)設(shè)置一個(gè)過期時(shí)間。但是對于這些訪問量很高的KEY,我們需要考慮一個(gè)問題:當(dāng)熱點(diǎn)KEY在失效的瞬間,海量的請求會(huì)不會(huì)產(chǎn)生大量的數(shù)據(jù)庫請求,從而導(dǎo)致數(shù)據(jù)庫崩潰?

  例如我們有一個(gè)業(yè)務(wù) KEY,該 KEY 的并發(fā)請求量為 10000。當(dāng)該 KEY 失效的時(shí)候,就會(huì)有 1 萬個(gè)線程會(huì)去請求數(shù)據(jù)庫更新緩存。這個(gè)時(shí)候如果沒有采取適當(dāng)?shù)拇胧敲磾?shù)據(jù)庫很可能崩潰。

  其實(shí)上面這個(gè)問題就是緩存擊穿的問題,它發(fā)生在緩存KEY的過期瞬間。對于這種情況,現(xiàn)在常用的解決方式有這么兩種:互斥鎖、永遠(yuǎn)不過期。

  互斥鎖

  互斥鎖指的是在緩存KEY過期去更新的時(shí)候,先讓程序去獲取鎖,只有獲取到鎖的線程才有資格去更新緩存KEY。其他沒有獲取到鎖的線程則休眠片刻之后再次去獲取最新的緩存數(shù)據(jù)。通過這種方式,同一時(shí)刻永遠(yuǎn)只有一個(gè)線程會(huì)去讀取數(shù)據(jù)庫,這樣也就避免了海量數(shù)據(jù)庫請求對于數(shù)據(jù)庫的沖擊。

  而對于上面說到的鎖,我們可以使用緩存提供的一些原則操作來完成。例如對于 redis 緩存來說,我們可以使用其 SETNX 命令來完成。

Java緩存設(shè)計(jì)要考慮哪些問題

  上面的 key_mutex 其實(shí)就是一個(gè)普通的 KEY-VALUE 值,我們使用 setnx 命令去設(shè)置其值為 1。如果這時(shí)候已經(jīng)有人在更新緩存KEY了,那么 setnx 命令會(huì)返回 0,表示設(shè)置失敗。

  永遠(yuǎn)不過期

  從緩存的角度來看,如果你設(shè)置了永遠(yuǎn)不過期,那么就不會(huì)有海量請求數(shù)據(jù)庫的情形出現(xiàn)。此時(shí)我們一般通過新起一個(gè)線程的方式去定時(shí)將數(shù)據(jù)庫中的數(shù)據(jù)更新到緩存中,更加成熟的方式是通過定時(shí)任務(wù)去同步緩存和數(shù)據(jù)庫的數(shù)據(jù)。

  但這種方案會(huì)出現(xiàn)數(shù)據(jù)的延遲問題,也就是線程讀取到的數(shù)據(jù)并不是最新的數(shù)據(jù)。但對于一般的互聯(lián)網(wǎng)功能來說,些許的延遲還是能接受的。

  緩存雪崩

  緩存雪崩是指在我們設(shè)置緩存時(shí)采用了相同的過期時(shí)間,導(dǎo)致緩存在某一時(shí)刻同時(shí)失效,請求全部轉(zhuǎn)發(fā)到數(shù)據(jù)庫,最終導(dǎo)致數(shù)據(jù)庫瞬時(shí)壓力過大而崩潰。

  例如我們有 1000 個(gè)KEY,而每個(gè) KEY 的并發(fā)請求不大,只有 10 次。而緩存雪崩指的就是這 1000 個(gè) KEY 在同一時(shí)間,同時(shí)失效,這個(gè)時(shí)候就突然有 1000 ** 10 = 一萬次查詢。

  緩存雪崩導(dǎo)致的問題一般很難排查,如果沒有事先預(yù)防,很可能要花很大力氣才能找得到原因。對于緩存雪崩的情況,最簡單的方案就是在原有失效時(shí)間的基礎(chǔ)上增加一個(gè)隨機(jī)時(shí)間(例如1-5分鐘),這樣每個(gè)緩存過期時(shí)間的重復(fù)率就會(huì)降低,從而減少緩存雪崩的發(fā)生。

  「緩存穿透」指的是請求不存在的數(shù)據(jù),從而使得緩存形同虛設(shè),緩存層被穿透了。例如我們請求一個(gè) UserID 為 -1 的用戶數(shù)據(jù),因?yàn)樵撚脩舨淮嬖?,所以該請求每次都?huì)去讀取數(shù)據(jù)庫。在這種情況下,如果某些心懷不軌的人利用這個(gè)存在的漏洞去偽造大量的請求,那么很可能導(dǎo)致DB承受不了那么大的流量就掛掉了。

  「緩存擊穿」指的是并發(fā)量很高的 KEY,在該 KEY 失效的瞬間有很多請求同同時(shí)去請求數(shù)據(jù)庫,更新緩存。例如我們有一個(gè)業(yè)務(wù) KEY,該 KEY 的并發(fā)請求量為 10000。當(dāng)該 KEY 失效的時(shí)候,就會(huì)有 1 萬個(gè)線程會(huì)去請求數(shù)據(jù)庫更新緩存。這個(gè)時(shí)候如果沒有采取適當(dāng)?shù)拇胧?,那么?shù)據(jù)庫很可能崩潰。

  「緩存雪崩」則是指緩存在同一時(shí)間同時(shí)過期,就像所有雪塊同一時(shí)刻掉下來,像雪崩一樣。例如我們有 1000 個(gè)KEY,而每個(gè) KEY 的并發(fā)請求不大,只有 10 次。而緩存雪崩指的就是這 1000 個(gè) KEY 在同一時(shí)間,同時(shí)失效,這個(gè)時(shí)候就突然有 1000 ** 10 = 一萬次查詢。

  對于它們出現(xiàn)的情形,我們可以做一些總結(jié):

  「緩存穿透」是業(yè)務(wù)層面的漏洞導(dǎo)致非法請求,與請求量、緩存失效沒關(guān)系?!妇彺鎿舸箘t只會(huì)出現(xiàn)在熱點(diǎn)數(shù)據(jù)上,發(fā)生在緩存失效的瞬間,與業(yè)務(wù)沒多大關(guān)系?!妇彺嫜┍馈箘t是因?yàn)槎鄠€(gè) KEY 同時(shí)失效,導(dǎo)致數(shù)據(jù)庫請求太多。非熱點(diǎn)數(shù)據(jù)也會(huì)導(dǎo)致緩存雪崩,只要同時(shí)失效的 KEY 足夠多。

到此,相信大家對“Java緩存設(shè)計(jì)要考慮哪些問題”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI