App下載

Java知識(shí)點(diǎn)詳解——緩存

猿友 2021-07-14 10:08:28 瀏覽數(shù) (7564)
反饋

如果沒(méi)有緩存,當(dāng)打開(kāi)一個(gè)有大量?jī)?nèi)容的頁(yè)面的時(shí)候,將會(huì)變得十分的卡頓,因?yàn)闆](méi)有緩存,每次打開(kāi)頁(yè)面的時(shí)候都進(jìn)行全部加載,而導(dǎo)致頁(yè)面打開(kāi)速度變得很慢,給用戶(hù)的體驗(yàn)也就十分的不愉快了。有了緩存,則會(huì)讓原本打開(kāi)很慢的頁(yè)面變得“秒開(kāi)”。那么緩存除了能夠加速數(shù)據(jù)的訪(fǎng)問(wèn)外,還有什么作用?本文將為您詳細(xì)介紹 java 緩存的運(yùn)放方式、緩存的類(lèi)別以及緩存會(huì)出現(xiàn)的問(wèn)題。

一、緩存能用來(lái)做什么?

大多數(shù)人對(duì)于緩存的理解就是,當(dāng)我們打開(kāi)一個(gè)頁(yè)面或是一個(gè)APP,當(dāng)它們打開(kāi)的速度很慢的時(shí)候,都會(huì)想到引入緩存,這樣打開(kāi)就會(huì)更快。

從技術(shù)這一方面來(lái)說(shuō),緩存之所以能夠提高訪(fǎng)問(wèn)速度,是因?yàn)榫彺媸腔趦?nèi)存去建立的。而內(nèi)存的讀寫(xiě)速度相對(duì)于硬盤(pán)是快很多的,所以用內(nèi)存代替硬盤(pán)作為讀寫(xiě)的介質(zhì),自然就會(huì)大大提升了訪(fǎng)問(wèn)數(shù)據(jù)的速度。

使用緩存的過(guò)程大致如下:

圖片13

二、運(yùn)用方式:預(yù)讀取和延遲寫(xiě)

除了上述的過(guò)程之外,緩存另外兩個(gè)重要的運(yùn)用方式:預(yù)讀取和延遲寫(xiě)。

2.1 預(yù)讀取

從字面意思來(lái)看就是預(yù)先讀取,實(shí)際意義也確實(shí)如此。預(yù)讀取就是提前把將要讀取的數(shù)據(jù)載入,也就是在系統(tǒng)中把硬盤(pán)中的一部分?jǐn)?shù)據(jù)提前加載到內(nèi)存中,然后對(duì)外提供服務(wù)。

圖片12

那么這么做的意義是什么?

因?yàn)橛行┫到y(tǒng)一旦啟動(dòng)就會(huì)有數(shù)以萬(wàn)計(jì)的請(qǐng)求涌進(jìn)來(lái),假設(shè)讓這些請(qǐng)求直接打到數(shù)據(jù)庫(kù)上,非常大的可能就是會(huì)讓數(shù)據(jù)庫(kù)的壓力劇增,數(shù)據(jù)庫(kù)就會(huì)被掛掉,而導(dǎo)致無(wú)法正常響應(yīng)。

預(yù)讀取就是為了解決這樣的問(wèn)題。

2.2 延遲寫(xiě)

如果說(shuō)預(yù)讀取就是在數(shù)據(jù)出口加一道緩沖區(qū),那么延遲寫(xiě)則是在數(shù)據(jù)入口加一道緩沖區(qū)。

由于數(shù)據(jù)庫(kù)的寫(xiě)入速度要比讀取速度慢,因此在寫(xiě)入的時(shí)候就需要一系列的保證數(shù)據(jù)正確性的機(jī)制。所以,要想提升寫(xiě)入速度,或是分庫(kù)分表,或是通過(guò)緩存加一道緩沖,再一次性批量寫(xiě)入磁盤(pán)。引入分庫(kù)分表的復(fù)雜度遠(yuǎn)大于引入緩存,一般都是優(yōu)先考慮引入緩存的方案。

這種緩存方案就是延遲寫(xiě),它是預(yù)先將準(zhǔn)備寫(xiě)入磁盤(pán)或數(shù)據(jù)庫(kù)的數(shù)據(jù),暫時(shí)寫(xiě)入到內(nèi)存,然后返回成功,再定時(shí)分批將內(nèi)存中的數(shù)據(jù)寫(xiě)入到磁盤(pán)。

圖片11

三、哪些可以加緩存?

在緩存之前需要考慮我們要緩存的是什么?符合什么樣特點(diǎn)的數(shù)據(jù)才需要加緩存?因?yàn)榫彺嫠闶且粋€(gè)額外的成本投入,所以加了緩存要體現(xiàn)它的價(jià)值。

先引入衡量數(shù)據(jù)的兩個(gè)標(biāo)準(zhǔn):

熱點(diǎn)數(shù)據(jù):被高頻訪(fǎng)問(wèn),如每秒幾十次以上。

靜態(tài)數(shù)據(jù):很少變動(dòng),讀取要大于寫(xiě)入。

以終端用戶(hù)為起點(diǎn),系統(tǒng)所使用的數(shù)據(jù)庫(kù)為終點(diǎn),這其中可以作為緩存設(shè)立點(diǎn)大致如下:

圖片10

每個(gè)設(shè)立點(diǎn)都會(huì)擋掉一些流量,最終會(huì)形成以下的漏斗形效果,以此可以保護(hù)后面的系統(tǒng)以及最后的數(shù)據(jù)庫(kù)。

圖片9

這些設(shè)立點(diǎn)就像是紅綠燈,如果沒(méi)有紅綠燈就容易發(fā)生事故,或是造成交通癱瘓等等。緩存設(shè)立點(diǎn)就是防止請(qǐng)求大量涌入,導(dǎo)致無(wú)法正常訪(fǎng)問(wèn)。

四、緩存類(lèi)別

上文已經(jīng)羅列了緩存的幾種類(lèi)別,接下我們將會(huì)對(duì)這些緩存類(lèi)別進(jìn)行介紹。

4.1 瀏覽器緩存

瀏覽器是離用戶(hù)最近的,可以用來(lái)作為緩存的地方,而且借助的是用戶(hù)的資源,性?xún)r(jià)比是幾種里面最好的,可以讓用戶(hù)分擔(dān)一些壓力。

進(jìn)入瀏覽器的開(kāi)發(fā)者工具,有 ?from cache? 、?from memory cache? 和? from disk cache? 的時(shí)候,說(shuō)明數(shù)據(jù)已經(jīng)被緩存在用戶(hù)的終端設(shè)備上,在沒(méi)網(wǎng)的時(shí)候也可能訪(fǎng)問(wèn)到一部分的內(nèi)容就是這個(gè)原因。

瀏覽器會(huì)幫助我們完成這個(gè)過(guò)程,一般適用于圖片、 js 和 css等這些資源的緩存。

瀏覽器緩存的劣勢(shì)就是我們對(duì)它的掌控力比較差,沒(méi)有發(fā)起新的請(qǐng)求的情況下,是無(wú)法主動(dòng)去更新數(shù)據(jù)。

4.2 CDN緩存

提供CDN服務(wù)的服務(wù)商,在全國(guó)乃至全世界部署了大量的服務(wù)節(jié)點(diǎn)。我們就可以將數(shù)據(jù)分發(fā)到遍布各地服務(wù)器上作為緩存,當(dāng)用戶(hù)訪(fǎng)問(wèn)時(shí)可以讀取就近的服務(wù)器上的緩存數(shù)據(jù)。這樣就可以分?jǐn)倝毫吞嵘思铀傩Ч?/p>

要注意的是,由于節(jié)點(diǎn)眾多,更新緩存數(shù)據(jù)會(huì)比較慢,一般至少是分鐘級(jí)別,所以該緩存適用于不經(jīng)常變動(dòng)的靜態(tài)數(shù)據(jù)。

4.3 網(wǎng)關(guān)(代理)緩存

我們經(jīng)常會(huì)在源站前面加上一層網(wǎng)管,目的是為了做一些安全機(jī)制或者作為同一分流策略的入口。

圖片8

在這里設(shè)立一個(gè)緩存,能夠攔下來(lái)請(qǐng)求,其背后的源站也是收益很大的,減少了大量的 CPU 運(yùn)算。常用的網(wǎng)關(guān)緩存有 ?Varnish?、?Squid?、?Nginx?。

4.4 進(jìn)程內(nèi)緩存

一個(gè)請(qǐng)求能夠到這里來(lái),說(shuō)明是“業(yè)務(wù)相關(guān)”,需要經(jīng)過(guò)業(yè)務(wù)邏輯的運(yùn)算。從這里開(kāi)始,對(duì)緩存的引入成本相對(duì)于前三者而言,要大大的增加了,這是因?yàn)閷?duì)緩存與數(shù)據(jù)庫(kù)之間的‘?dāng)?shù)據(jù)一致性’要求更高了。

4.5 進(jìn)程外緩存

這里是大多數(shù)程序員所熟悉的地方,就是 ?Redis? 和? Memcached? 之類(lèi),或者也可以自己?jiǎn)为?dú)寫(xiě)一個(gè)程序來(lái)轉(zhuǎn)存放緩存數(shù)據(jù),提供給其他程序遠(yuǎn)程調(diào)用。

4.6 數(shù)據(jù)庫(kù)緩存

數(shù)據(jù)庫(kù)緩存是數(shù)據(jù)庫(kù)的內(nèi)部機(jī)制,一般都會(huì)給出設(shè)置緩存空間大小的配置來(lái)讓你進(jìn)行干預(yù)。

最后,磁盤(pán)本身也是有緩存的,所以能夠讓數(shù)據(jù)平穩(wěn)地寫(xiě)入到磁盤(pán),可謂是經(jīng)歷了一波三折。

五、緩存可能出現(xiàn)的問(wèn)題

既然緩存作用如此大,那是不是就越多越好呢?只要速度慢就加緩存來(lái)解決?其實(shí)不然,緩存既有好的一面,也會(huì)有負(fù)面的一面。

5.1 緩存雪崩

問(wèn)題:大量請(qǐng)求并發(fā)進(jìn)入緩存時(shí),可能由于某些原因緩沖效果未能正常執(zhí)行,即便是在很短的時(shí)間內(nèi),就會(huì)導(dǎo)致請(qǐng)求全部轉(zhuǎn)入數(shù)據(jù)庫(kù),從而造成數(shù)據(jù)庫(kù)壓力過(guò)重。

解決:可以通過(guò)“加鎖排隊(duì)”或者“緩存時(shí)間增加隨機(jī)值”來(lái)解決此類(lèi)問(wèn)題。

5.2 緩存穿透

和緩存雪崩很相似,區(qū)別在于穿透會(huì)持續(xù)更長(zhǎng)的時(shí)間。這是因?yàn)槊看蔚? cache miss? 后依然無(wú)法從數(shù)據(jù)源把數(shù)據(jù)加載到緩存,導(dǎo)致持續(xù)產(chǎn)生cache miss?。

可以通過(guò)“布隆過(guò)濾器”或者“緩存空對(duì)象”來(lái)解決此類(lèi)問(wèn)題。

5.3 緩存并發(fā)

一個(gè)緩存 ?key ?下的數(shù)據(jù)被同時(shí) ?set?,怎么保證業(yè)務(wù)的準(zhǔn)確性?如果進(jìn)程內(nèi)、進(jìn)程外、數(shù)據(jù)庫(kù)三者的緩存一起用的情況下?

使用“先DB再緩存”的方式,并且緩存操作用 delete 而不是 set。

5.4 緩存無(wú)底洞

雖然分布式緩存是可以無(wú)線(xiàn)橫向擴(kuò)展的,但是,集群下的節(jié)點(diǎn)也不是越多越好。緩存也是符合“邊際效用遞減”規(guī)律的。

5.5 緩存淘汰

內(nèi)存的容量是有限的,如果請(qǐng)求的數(shù)據(jù)量是大量的,那么根據(jù)具體情況進(jìn)行一定的淘汰策略是必不可少的。例如:?LRU?、?LFU?和?FIFO?等等。

六、總結(jié)

本文主要介紹了Java緩存的運(yùn)用方式的三種思路,Java緩存的類(lèi)別,在系統(tǒng)中可以設(shè)立緩存的幾個(gè)位置,以及最后總結(jié)了 Java 緩存中會(huì)遇到的問(wèn)題。如果想對(duì)文章中的具體細(xì)節(jié)有更多的了解,請(qǐng)關(guān)注 w3cschool 或 編程獅APP。


0 人點(diǎn)贊