java基礎(chǔ)專(zhuān)欄今天介紹java高並發(fā)系統(tǒng)設(shè)計(jì)的快取篇。
常見(jiàn)硬體元件的延時(shí)情況如下圖:
從這些資料中,你可以看到,做一次內(nèi)存尋址大概需要100ns,而做一次磁碟的查找則需要10ms??梢?jiàn),我們使用記憶體作為快取的儲(chǔ)存媒體相比於以磁碟作為主要儲(chǔ)存媒體的資料庫(kù)來(lái)說(shuō),效能上會(huì)提高多個(gè)數(shù)量級(jí)。所以,記憶體是最常見(jiàn)的一種快取資料的媒體。
一、快取案例
1、TLB
Linux 記憶體管理是透過(guò)一個(gè)叫做MMU(Memory Management Unit)的硬件,來(lái)實(shí)現(xiàn)從虛擬位址到物理位址的轉(zhuǎn)換的,但是如果每次轉(zhuǎn)換都要做這麼複雜計(jì)算的話,無(wú)疑會(huì)造成性能的損耗,所以我們會(huì)藉助一個(gè)叫做TLB(Translation Lookaside Buffer)的組件來(lái)緩存最近轉(zhuǎn)換過(guò)的虛擬地址,和物理地址的映射。 TLB 就是一種快取元件。
2、抖音
平臺(tái)上的短影片其實(shí)是使用內(nèi)建的網(wǎng)路播放器來(lái)完成的。網(wǎng)路播放器接收的是資料流,將資料下載下來(lái)之後經(jīng)過(guò)分離音視訊串流,解碼等流程後輸出到週邊設(shè)備上播放。播放器中通常會(huì)設(shè)計(jì)一些快取的組件,在未打開(kāi)視頻時(shí)緩存一部分視頻數(shù)據(jù),比如我們打開(kāi)抖音,服務(wù)端可能一次會(huì)返回三個(gè)視頻信息,我們?cè)诓シ诺谝粋€(gè)視頻的時(shí)候,播放器已經(jīng)幫我們快取了第二、三個(gè)影片的部分?jǐn)?shù)據(jù),這樣在看第二個(gè)影片的時(shí)候就可以給用戶「秒開(kāi)」的感覺(jué)。
3、HTTP協(xié)定快取
當(dāng)我們第一次要求靜態(tài)的資源時(shí),例如一張圖片,服務(wù)端除了回傳圖片訊息,在回應(yīng)頭裡面還有一個(gè)「Etag”的字段。瀏覽器會(huì)快取圖片資訊以及這個(gè)欄位的值。當(dāng)下次再要求這個(gè)圖片的時(shí)候,瀏覽器發(fā)起的請(qǐng)求頭裡面會(huì)有一個(gè)「If-None-Match」的字段,並且把快取的「Etag」的值寫(xiě)進(jìn)去發(fā)給服務(wù)端。服務(wù)端比對(duì)圖片資訊是否有變化,如果沒(méi)有,則傳回瀏覽器一個(gè) 304 的狀態(tài)碼,瀏覽器會(huì)繼續(xù)使用快取的圖片資訊。透過(guò)這種快取協(xié)商的方式,可以減少網(wǎng)路傳輸?shù)馁Y料大小,進(jìn)而提升頁(yè)面展示效能。
二、快取分類(lèi)
1、靜態(tài)快取
靜態(tài)快取在Web 1.0 時(shí)期是非常著名的,它一般透過(guò)產(chǎn)生Velocity 範(fàn)本或靜態(tài)HTML 文件來(lái)實(shí)現(xiàn)靜態(tài)緩存,在Nginx 上部署靜態(tài)緩存可以減少對(duì)於後臺(tái)應(yīng)用伺服器的壓力
2、分佈式緩存
分佈式緩存的大名可謂是如雷貫耳了,我們平時(shí)耳熟能詳?shù)腗emcached、Redis 就是分散式快取的典型例子。它們性能強(qiáng)勁,透過(guò)一些分散式的方案組成集群可以突破單機(jī)的限制。所以在整體架構(gòu)中,分散式快取承擔(dān)著非常重要的角色
3、本地快取
Guava Cache 或者是Ehcache 等,它們和應(yīng)用程式部署在同一個(gè)進(jìn)程中,優(yōu)勢(shì)是不需要跨網(wǎng)路調(diào)度,速度極快,所以可以用來(lái)阻擋短時(shí)間內(nèi)的熱點(diǎn)查詢。
三、快取的讀寫(xiě)策略
1、Cache Aside策略
#在更新資料時(shí)不更新緩存,而是刪除快取中的數(shù)據(jù),在讀取數(shù)據(jù)時(shí),發(fā)現(xiàn)快取中沒(méi)了數(shù)據(jù)之後,再?gòu)馁Y料庫(kù)讀取數(shù)據(jù),更新到快取中。
這個(gè)策略就是我們使用快取最常見(jiàn)的策略,Cache Aside 策略(也叫旁路快取策略),這個(gè)策略資料以資料庫(kù)中的資料為準(zhǔn),快取中的資料是按需加載的。
Cache Aside 策略是我們?nèi)粘i_(kāi)發(fā)中最常使用的快取策略,不過(guò)我們?cè)谑褂脮r(shí)也要學(xué)會(huì)依情況而變,並不是一成不變的。 Cache Aside 存在的最大的問(wèn)題是當(dāng)寫(xiě)入比較頻繁時(shí),快取中的資料會(huì)被頻繁地清理,這會(huì)對(duì)快取的命中率有一些影響。如果你的業(yè)務(wù)對(duì)快取命中率有嚴(yán)格的要求,那麼可以考慮兩個(gè)解決方案:
一種做法是在更新資料時(shí)也更新緩存,只是在更新緩存前先加一個(gè)分散式鎖,因?yàn)檫@樣在同一時(shí)間只允許一個(gè)執(zhí)行緒更新緩存,就不會(huì)產(chǎn)生並發(fā)問(wèn)題了。當(dāng)然這麼做對(duì)於寫(xiě)入的性能會(huì)有一些影響(推薦);
另一種做法同樣也是在更新數(shù)據(jù)時(shí)更新緩存,只是給緩存加一個(gè)較短的過(guò)期時(shí)間,這樣即使出現(xiàn)緩存不一致的情況,快取的資料也會(huì)很快過(guò)期,對(duì)業(yè)務(wù)的影響也可以接受。
2、Read/Write Through
這個(gè)策略的核心原則是使用者只與快取打交道,由快取和資料庫(kù)通信,寫(xiě)入或讀取資料。
Write Through
的策略是這樣的:先查詢要寫(xiě)入的資料在快取中是否已經(jīng)存在,如果已經(jīng)存在,則更新緩存中的數(shù)據(jù),並且由快取元件同步更新到資料庫(kù)中,如果快取中資料不存在,我們把這種情況叫做「Write Miss(寫(xiě)失效)」。一般來(lái)說(shuō),我們可以選擇兩種“Write Miss”方式:一個(gè)是“Write Allocate(按寫(xiě)分配)”,做法是寫(xiě)入快取對(duì)應(yīng)位置,再由快取元件同步更新到資料庫(kù)中;另一個(gè)是“No -write allocate(不按寫(xiě)分配)”,做法是不寫(xiě)入快取中,而是直接更新到資料庫(kù)中。 我們看到 Write Through 策略中寫(xiě)入資料庫(kù)是同步的,這對(duì)於效能來(lái)說(shuō)會(huì)有比較大的影響,因?yàn)橄噍^於寫(xiě)入緩存,同步寫(xiě)入資料庫(kù)的延遲就要高很多了。透過(guò)Write Back策略異步的更新資料庫(kù)。
Read Through
策略就簡(jiǎn)單一些,它的步驟是這樣的:先查詢快取中資料是否存在,如果存在則直接傳回,如果不存在,則由快取元件負(fù)責(zé)從資料庫(kù)同步載入資料。
3、Write Back
這個(gè)策略的核心思想是在寫(xiě)入資料時(shí)只寫(xiě)入緩存,並且把快取區(qū)塊兒標(biāo)記為「髒」的。而髒塊兒只有在再次使用時(shí)才會(huì)將其中的資料寫(xiě)入後端儲(chǔ)存。
在「Write Miss」的情況下,我們採(cǎi)用的是「Write Allocate」的方式,也就是在寫(xiě)入後端儲(chǔ)存的同時(shí)要寫(xiě)入緩存,這樣我們?cè)谥岬膶?xiě)入請(qǐng)求中都只需要更新快取即可,而無(wú)需更新後端儲(chǔ)存了。注意與上面的write through策略作區(qū)分。
我們?cè)谧x取快取時(shí)如果發(fā)現(xiàn)快取命中則直接傳回快取資料。如果快取不命中則尋找一個(gè)可用的快取區(qū)塊兒,如果這個(gè)快取區(qū)塊兒是「髒」的,就把快取區(qū)塊兒中之前的資料寫(xiě)入到後端儲(chǔ)存中,並且從後端儲(chǔ)存載入資料到快取塊兒,如果不是髒的,則由快取元件將後端儲(chǔ)存中的資料載入到快取中,最後我們將快取設(shè)定為不是髒的,回傳資料就好了。
write back策略多用於向磁碟中寫(xiě)入資料。例如:作業(yè)系統(tǒng)層面的 Page Cache、日誌的非同步刷盤(pán)、訊息佇列中訊息的非同步寫(xiě)入磁碟等。因?yàn)檫@個(gè)策略在效能上的優(yōu)勢(shì)毋庸置疑,它避免了直接寫(xiě)磁碟造成的隨機(jī)寫(xiě)入問(wèn)題,畢竟寫(xiě)記憶體和寫(xiě)入磁碟的隨機(jī) I/O 的延遲相差了幾個(gè)數(shù)量級(jí)呢。
四、快取高可用
快取的命中率是快取需要監(jiān)控的資料指標(biāo),快取的高可用可以一定程度上減少快取穿透的機(jī)率,提升系統(tǒng)的穩(wěn)定性??烊〉母呖捎梅桨钢饕蛻舳朔桨?、中間代理層方案和服務(wù)端方案三大類(lèi):
1、客戶端方案
在客戶端方案中,你需要專(zhuān)注於緩存的寫(xiě)和讀兩方面: 寫(xiě)入資料時(shí),需要把寫(xiě)入快取的資料分散到多個(gè)節(jié)點(diǎn)中,即進(jìn)行資料分片; 讀取資料時(shí),可以利用多組的快取來(lái)做容錯(cuò),提升快取系統(tǒng)的可用性。關(guān)於讀取數(shù)據(jù),這裡可以使用主從和多副本兩種策略,兩種策略是為了解決不同的問(wèn)題而提出的。 具體的實(shí)作細(xì)節(jié)包括:資料分片、主從、多副本
資料分片
一致性Hash演算法。在這個(gè)演算法中,我們將整個(gè) Hash 值空間組織成一個(gè)虛擬的圓環(huán),然後將快取節(jié)點(diǎn)的 IP 位址或主機(jī)名稱做 Hash 取值後,就放置在這個(gè)圓環(huán)上。當(dāng)我們需要確定某一個(gè)Key 需要訪問(wèn)到哪個(gè)節(jié)點(diǎn)上的時(shí)候,先對(duì)這個(gè)Key 做同樣的Hash 取值,確定在環(huán)上的位置,然後按照順時(shí)針?lè)较蛟诃h(huán)上“行走”,遇到的第一個(gè)快取節(jié)點(diǎn)就是要存取的節(jié)點(diǎn)。
這時(shí)如果在Node 1 和Node 2 之間增加一個(gè)Node 5,你可以看到原本命中Node 2 的Key 3 現(xiàn)在命中到Node 5,而其它的Key 都沒(méi)有變化;同樣的道理,如果我們把Node 3 從叢集中移除,只會(huì)影響到Key 5 。所以你看,在增加和刪除節(jié)點(diǎn)時(shí),只有少量的 Key 會(huì)「漂移」到其它節(jié)點(diǎn)上,而大部分的 Key 命中的節(jié)點(diǎn)還是會(huì)保持不變,從而可以保證命中率不會(huì)大幅下降。 【提示】一致性hash出現(xiàn)的快取雪崩現(xiàn)象使用虛擬節(jié)點(diǎn)解決。一致性hash分片與hash分片的差別在於,快取命中率的問(wèn)題,hash分片在存在機(jī)器加入或是減少的情況時(shí)候,會(huì)導(dǎo)致快取失效,快取命中率下降。
主從
Redis 本身支援主從的部署方式,但是 Memcached 並不支持,Memcached 的主從機(jī)制是如何在客戶端實(shí)現(xiàn)的。為每一組 Master 設(shè)定一組 Slave,更新資料時(shí)主從同步更新。讀取時(shí),優(yōu)先從 Slave 中讀數(shù)據(jù),如果讀取不到數(shù)據(jù)就穿透到 Master 讀取,並且將數(shù)據(jù)回種到 Slave 中以保持 Slave 數(shù)據(jù)的熱度。主從機(jī)制最大的優(yōu)點(diǎn)就是當(dāng)某一個(gè) Slave 宕機(jī)時(shí),還會(huì)有 Master 作為兜底,不會(huì)有大量請(qǐng)求穿透到資料庫(kù)的情況發(fā)生,提升了快取系統(tǒng)的高可用性。
多重複製
主從方式已經(jīng)能夠解決大部分場(chǎng)景的問(wèn)題,但是對(duì)於極端流量的場(chǎng)景下,一組Slave 通常來(lái)說(shuō)並不能完全承擔(dān)所有流量,Slave 網(wǎng)路卡頻寬可能成為瓶頸。為了解決這個(gè)問(wèn)題,我們考慮在Master/Slave 之前增加一層副本層,整體架構(gòu)是這樣的:
這個(gè)方案中,當(dāng)客戶端發(fā)起查詢請(qǐng)求時(shí),請(qǐng)求首先會(huì)先從在多個(gè)副本群組中選取一個(gè)副本群組發(fā)起查詢,如果查詢失敗,就繼續(xù)查詢Master/Slave,並且將查詢的結(jié)果回種到所有副本群組中,避免副本群組中髒資料的存在?;冻杀镜目紤],每個(gè)副本組容量比 Master 和 Slave 要小,因此它只儲(chǔ)存了更加熱的資料。在這套架構(gòu)中,Master 和 Slave 的請(qǐng)求量會(huì)大幅減少,為了確保它們儲(chǔ)存資料的熱度,在實(shí)務(wù)上我們會(huì)把 Master 和 Slave 作為一組副本組使用。
2、中間代理層
業(yè)界也有很多中間代理層方案,像是 Facebook 的Mcrouter,Twitter 的Twemproxy,豌豆莢的Codis。它們的原理基本上可以由一張圖來(lái)概括:
3、服務(wù)端方案
Redis 在2.4 版本中提出了Redis Sentinel 模式來(lái)解決主從Redis 部署時(shí)的高可用問(wèn)題,它可以在主節(jié)點(diǎn)掛了以後自動(dòng)將從節(jié)點(diǎn)提升為主節(jié)點(diǎn),保證整體叢集的可用性,整體的架構(gòu)如下圖所示:
redis Sentinel 也是叢集部署的,這樣可以避免Sentinel 節(jié)點(diǎn)掛掉造成無(wú)法自動(dòng)故障復(fù)原的問(wèn)題,每一個(gè)Sentinel 節(jié)點(diǎn)都是無(wú)狀態(tài)的。在Sentinel 中會(huì)配置Master 的位址,Sentinel 會(huì)時(shí)時(shí)刻刻監(jiān)控Master 的狀態(tài),當(dāng)發(fā)現(xiàn)Master 在設(shè)定的時(shí)間間隔內(nèi)無(wú)回應(yīng),就認(rèn)為Master 已經(jīng)掛了,Sentinel 會(huì)從從節(jié)點(diǎn)中選取一個(gè)提升為主節(jié)點(diǎn),並且把所有其他的從節(jié)點(diǎn)作為新主的從節(jié)點(diǎn)。 Sentinel 叢集內(nèi)部在仲裁的時(shí)候,會(huì)根據(jù)配置的值來(lái)決定當(dāng)有幾個(gè) Sentinel 節(jié)點(diǎn)認(rèn)為主掛掉可以做主從切換的操作,也就是叢集內(nèi)部需要對(duì)快取節(jié)點(diǎn)的狀態(tài)達(dá)成一致才行。
【提示】上述客戶端到sentinel叢集的連線是虛線,因?yàn)閷?duì)於快取的寫(xiě)入和讀取請(qǐng)求不會(huì)經(jīng)過(guò) Sentinel 節(jié)點(diǎn)。
五、快取穿透
1、帕累托
網(wǎng)路系統(tǒng)的資料存取模型一般會(huì)遵從「80/20 原則」。 「80/20 原則」又稱為帕累託法則,是義大利經(jīng)濟(jì)學(xué)家帕累托提出的經(jīng)濟(jì)學(xué)的理論。簡(jiǎn)單來(lái)說(shuō),它是指在一組事物中,最重要的部分通常只佔(zhàn) 20%,而其他的 80% 並沒(méi)有那麼重要。把它應(yīng)用到數(shù)據(jù)存取的領(lǐng)域,就是我們會(huì)經(jīng)常存取 20% 的熱點(diǎn)數(shù)據(jù),而另外的 80% 的數(shù)據(jù)則不會(huì)被經(jīng)常存取。既然快取的容量有限,而且大部分的存取只會(huì)請(qǐng)求20% 的熱點(diǎn)數(shù)據(jù),那麼理論上說(shuō),我們只需要在有限的快取空間裡儲(chǔ)存20% 的熱點(diǎn)資料就可以有效地保護(hù)脆弱的後端系統(tǒng)了,也就可以放棄快取另外80% 的非熱點(diǎn)資料了。所以這種少量的緩存穿透是不可避免的,但是對(duì)系統(tǒng)是沒(méi)有損害的。
2、回種空值
當(dāng)我們從資料庫(kù)中查詢到空值或發(fā)生異常時(shí),我們可以向快取中回種一個(gè)空值。但是因?yàn)榭罩祦K不是準(zhǔn)確的業(yè)務(wù)數(shù)據(jù),並且會(huì)佔(zhàn)用快取的空間,所以我們會(huì)為這個(gè)空值加一個(gè)比較短的過(guò)期時(shí)間,讓空值在短時(shí)間內(nèi)能夠快速過(guò)期淘汰。回種空值雖然能夠阻擋大量穿透的請(qǐng)求,但如果有大量的空值緩存,也會(huì)浪費(fèi)緩存的存儲(chǔ)空間,如果緩存空間被佔(zhàn)滿了,還會(huì)剔除掉一些已經(jīng)被緩存的用戶信息反而會(huì)造成快取命中率的下降。所以這個(gè)方案,我建議你在使用的時(shí)候應(yīng)該評(píng)估緩存容量是否能夠支撐。如果需要大量的快取節(jié)點(diǎn)來(lái)支持,那麼就無(wú)法透過(guò)回種空值的方式來(lái)解決,這時(shí)你可以考慮使用布隆過(guò)濾器。
3、布隆過(guò)濾器
1970 年布隆提出了一個(gè)布林過(guò)濾器的演算法,用來(lái)判斷一個(gè)元素是否在一個(gè)集合中。這種演算法由一個(gè)二進(jìn)制數(shù)組和一個(gè) Hash 演算法組成。它的基本想法如下:我們把集合中的每一個(gè)值按照提供的Hash 演算法算出對(duì)應(yīng)的Hash 值,然後將Hash 值對(duì)數(shù)組長(zhǎng)度取模後得到需要計(jì)入數(shù)組的索引值,並且將數(shù)組這個(gè)位置的值從0 改成1。在判斷一個(gè)元素是否存在於這個(gè)集合中時(shí),你只需要將這個(gè)元素依照相同的演算法計(jì)算出索引值,如果這個(gè)位置的值為 1 就認(rèn)為這個(gè)元素在集合中,否則則認(rèn)為不在集合中。
如何使用布隆過(guò)濾器解決快取穿透呢?
以儲(chǔ)存使用者資訊的表格為例進(jìn)行講解。首先我們初始化一個(gè)很大的數(shù)組,比方說(shuō)長(zhǎng)度為20 億的數(shù)組,接下來(lái)我們選擇一個(gè)Hash 演算法,然後我們將目前現(xiàn)有的所有用戶的ID 計(jì)算出Hash 值並且映射到這個(gè)大數(shù)組中,映射位置的值設(shè)定為1,其它值設(shè)定為0。新註冊(cè)的用戶除了需要寫(xiě)入資料庫(kù)之外,它也需要依照相同的演算法更新布隆過(guò)濾器的陣列中對(duì)應(yīng)位置的值。那麼當(dāng)我們需要查詢某一個(gè)用戶的資訊時(shí),先查詢這個(gè)ID 在布隆過(guò)濾器中是否存在,如果不存在就直接返回空值,而不需要繼續(xù)查詢資料庫(kù)和緩存,這樣就可以大大減少異常查詢帶來(lái)的快取穿透。
布隆過(guò)濾器優(yōu)點(diǎn):
(1)效能高。無(wú)論是寫(xiě)入操作還是讀取操作,時(shí)間複雜度都是 O(1) 是常數(shù)值
(2)節(jié)省空間。例如,20 億的數(shù)組需要2000000000/8/1024/1024 = 238M 的空間,而如果使用數(shù)組來(lái)存儲(chǔ),假設(shè)每個(gè)用戶ID 佔(zhàn)用4 個(gè)字節(jié)的空間,那麼存儲(chǔ)20 億用戶需要2000000000 * 4 / 1024 / 1024 = 7600M 的空間,是布隆過(guò)濾器的32 倍。
布隆過(guò)濾器缺點(diǎn):
(1)它在判斷元素是否在集合中時(shí)是有一定錯(cuò)誤幾率的,例如它會(huì)把不是集合中的元素判斷為處在集合中。
原因:Hash演算法本身的缺陷。
解決方案:使用多個(gè) Hash 演算法為元素計(jì)算出多個(gè) Hash 值,只有所有 Hash 值對(duì)應(yīng)的陣列中的值都為 1 時(shí),才會(huì)認(rèn)為這個(gè)元素在集合中。
(2)不支援刪除元素。布隆過(guò)濾器不支援刪除元素的缺陷也和 Hash 碰撞有關(guān)。舉一個(gè)例子,假如兩個(gè)元素 A 和 B 都是集合中的元素,它們有相同的 Hash 值,它們就會(huì)對(duì)應(yīng)到陣列的同一個(gè)位置。這時(shí)我們刪除了 A,陣列中對(duì)應(yīng)位置的值也從 1 變成 0,那麼在判斷 B 的時(shí)候發(fā)現(xiàn)值是 0,也會(huì)判斷 B 是不在集合中的元素,就會(huì)得到錯(cuò)誤的結(jié)論。
解決方案:我會(huì)讓陣列中不再只有 0 和 1 兩個(gè)值,而是儲(chǔ)存一個(gè)計(jì)數(shù)。例如如果 A 和 B 同時(shí)命中了一個(gè)陣列的索引,那麼這個(gè)位置的值就是 2,如果 A 被刪除了就把這個(gè)值從 2 改為 1。這個(gè)方案中的陣列不再儲(chǔ)存 bit 位,而是儲(chǔ)存數(shù)值,也會(huì)增加空間的消耗。
4、狗樁效應(yīng)
比方說(shuō)當(dāng)有一個(gè)極熱點(diǎn)的緩存項(xiàng),它一旦失效會(huì)有大量請(qǐng)求穿透到資料庫(kù),這會(huì)對(duì)資料庫(kù)造成瞬時(shí)極大的壓力,我們把這個(gè)場(chǎng)景叫做「dog-pile effect」(狗樁效應(yīng))。解決狗樁效應(yīng)的想法是盡量減少緩存穿透後的並發(fā),方案也比較簡(jiǎn)單:
(1)在程式碼中控制在某一個(gè)熱點(diǎn)緩存項(xiàng)目失效之後啟動(dòng)一個(gè)後臺(tái)線程,穿透到資料庫(kù),將資料載入到快取中,在快取未載入之前,所有存取這個(gè)快取的請(qǐng)求都不再穿透而直接返回。
(2)透過(guò)在Memcached 或Redis 中設(shè)定分散式鎖,只有取得到鎖的請(qǐng)求才能夠穿透到資料庫(kù)
六、CDN
##1、靜態(tài)資源加速的原因在我們的系統(tǒng)中存在著大量的靜態(tài)資源請(qǐng)求:對(duì)於行動(dòng)APP 來(lái)說(shuō),這些靜態(tài)資源主要是圖片、影片和串流媒體資訊;對(duì)於Web 網(wǎng)站來(lái)說(shuō),則包括了JavaScript 檔案、CSS 檔案、靜態(tài)HTML 檔案等等。它們的讀取請(qǐng)求量極大並且對(duì)訪問(wèn)速度的要求很高還佔(zhàn)據(jù)了很高的頻寬,這時(shí)會(huì)出現(xiàn)訪問(wèn)速度慢頻寬被佔(zhàn)滿影響動(dòng)態(tài)請(qǐng)求的問(wèn)題,那麼你就需要考慮如何針對(duì)這些靜態(tài)資源進(jìn)行讀加速了。 2、CDN靜態(tài)資源存取的關(guān)鍵點(diǎn)是就近訪問(wèn),即北京用戶訪問(wèn)北京的數(shù)據(jù),杭州用戶訪問(wèn)杭州的數(shù)據(jù),這樣才可以達(dá)到性能的最優(yōu)。我們考慮在業(yè)務(wù)伺服器的上層增加一層特殊的緩存,用來(lái)承擔(dān)絕大部分對(duì)於靜態(tài)資源的訪問(wèn),這一層特殊緩存的節(jié)點(diǎn)需要遍布在全國(guó)各地,這樣可以讓用戶選擇最近的節(jié)點(diǎn)訪問(wèn)??烊〉拿新室残枰欢ǖ谋WC,盡量減少存取資源儲(chǔ)存源站的請(qǐng)求數(shù)量(回源請(qǐng)求)。這一層快取就是CDN。 CDN(Content Delivery Network/Content Distribution Network,內(nèi)容傳遞網(wǎng)路)。簡(jiǎn)單來(lái)說(shuō),CDN 是將靜態(tài)的資源分發(fā)到位於多個(gè)地理位置機(jī)房中的伺服器上,因此它能很好地解決資料就近存取的問(wèn)題,也就加快了靜態(tài)資源的存取速度。 3、建構(gòu)CDN系統(tǒng)建構(gòu)一個(gè)CDN 系統(tǒng)需要考慮哪兩點(diǎn):(1)如何將使用者的請(qǐng)求對(duì)應(yīng)到CDN 節(jié)點(diǎn)上
你可能會(huì)覺(jué)得這很簡(jiǎn)單啊,只需要告訴用戶CDN 節(jié)點(diǎn)的IP 位址,然後請(qǐng)求這個(gè)IP 位址上面部署的CDN 服務(wù)就可以了啊。但是,並不是這樣,需要把ip替換為對(duì)應(yīng)的網(wǎng)域。那麼如何做到這一點(diǎn)呢?這就需要依賴 DNS 來(lái)幫我們解決網(wǎng)域?qū)τ车膯?wèn)題了。 DNS(Domain Name System,網(wǎng)域名稱系統(tǒng))其實(shí)就是一個(gè)儲(chǔ)存網(wǎng)域名稱和 IP 位址對(duì)應(yīng)關(guān)係的分散式資料庫(kù)。而域名解析的結(jié)果一般有兩種,一種叫做“A 記錄”,返回的是域名對(duì)應(yīng)的IP 位址;另一種是“CNAME 記錄”,返回的是另一個(gè)域名,也就是說(shuō)當(dāng)前域名的解析要跳到另一個(gè)網(wǎng)域的解析上。 舉個(gè)例子:例如你的公司的一級(jí)網(wǎng)域叫做example.com,那麼你可以把你的圖片服務(wù)的網(wǎng)域定義為“img.example.com”,然後將這個(gè)網(wǎng)域的解析結(jié)果的CNAME 配置到CDN 提供的網(wǎng)域上,例如uclound 可能會(huì)提供一個(gè)網(wǎng)域是「80f21f91.cdn.ucloud.com.cn」這個(gè)網(wǎng)域。這樣你的電商系統(tǒng)使用的圖片位址可以是「img.example.com/1.jpg」。 使用者在要求這個(gè)位址時(shí),DNS 伺服器會(huì)將網(wǎng)域名稱解析到80f21f91.cdn.ucloud.com.cn 網(wǎng)域上,然後再將這個(gè)網(wǎng)域解析為CDN 的節(jié)點(diǎn)IP,這樣就可以得到CDN 上面的資源數(shù)據(jù)了。網(wǎng)域?qū)蛹?jí)解析最佳化
因?yàn)榫W(wǎng)域解析過(guò)程是分級(jí)的,每一層有專(zhuān)門(mén)的網(wǎng)域名稱伺服器承擔(dān)解析的職責(zé),所以網(wǎng)域的解析過(guò)程有可能需要跨越公網(wǎng)做多次DNS 查詢,在效能上是比較差的。一個(gè)解決的想法是:在 APP 啟動(dòng)時(shí)對(duì)需要解析的網(wǎng)域做預(yù)先解析,然後把解析的結(jié)果快取到本地的一個(gè) LRU 快取裡面。這樣當(dāng)我們要使用這個(gè)網(wǎng)域的時(shí)候,只需要從快取直接拿到所需要的 IP 位址就好了,如果快取中不存在才會(huì)走整個(gè) DNS 查詢的過(guò)程。同時(shí)為了避免 DNS 解析結(jié)果的變更造成快取內(nèi)資料失效,我們可以啟動(dòng)計(jì)時(shí)器定期更新快取中的資料。 (2)如何根據(jù)使用者的地理位置資訊選擇到比較近的節(jié)點(diǎn)。GSLB(Global Server Load Balance,全域負(fù)載平衡)的意思是對(duì)於部署在不同地域的伺服器之間做負(fù)載平衡,下面可能管理了很多的本地負(fù)載平衡元件。它有兩方面的作用:一方面,它是一種負(fù)載平衡伺服器,負(fù)載平衡,顧名思義嘛,指的是讓流量平均分配使得下面管理的伺服器的負(fù)載更平均;另一方面,它還需要保證流量流經(jīng)的伺服器與流量源頭在地緣上是比較接近的。
GSLB 可以透過(guò)多種策略來(lái)保證傳回的CDN 節(jié)點(diǎn)和使用者盡量保證在同一地緣區(qū)域,比如說(shuō)可以將使用者的IP 位址依照地理位置劃分為若干個(gè)區(qū)域,然後將CDN 節(jié)點(diǎn)對(duì)應(yīng)到在一個(gè)區(qū)域上,根據(jù)使用者所在區(qū)域來(lái)傳回適當(dāng)?shù)墓?jié)點(diǎn);也可以透過(guò)發(fā)送資料包測(cè)量RTT 的方式來(lái)決定傳回哪一個(gè)節(jié)點(diǎn)。
總結(jié):DNS 技術(shù)是CDN 實(shí)作中使用的核心技術(shù),可以將使用者的請(qǐng)求映射到CDN 節(jié)點(diǎn)上;DNS 解析結(jié)果需要做本地緩存,降低DNS 解析過(guò)程的回應(yīng)時(shí)間;GSLB 可以給用戶回傳一個(gè)離他更近的節(jié)點(diǎn),加快靜態(tài)資源的存取速度。
拓展
(1)百度網(wǎng)域的解析過(guò)程
一開(kāi)始,網(wǎng)域解析請(qǐng)求先會(huì)檢查本機(jī)的hosts 文件,查看是否有www.baidu.com 對(duì)應(yīng)的IP;如果沒(méi)有的話,就請(qǐng)求Local DNS 是否有域名解析結(jié)果的緩存,如果有就返回標(biāo)識(shí)是從非權(quán)威DNS 返回的結(jié)果;如果沒(méi)有就開(kāi)始DNS 的迭代查詢。先請(qǐng)求根DNS,根DNS 回傳頂級(jí)DNS(.com)的位址;再請(qǐng)求.com 頂級(jí)DNS 得到baidu.com 的網(wǎng)域名稱伺服器位址;再?gòu)腷aidu.com 的網(wǎng)域伺服器查詢到www.baidu.com 對(duì)應(yīng)的IP 位址,傳回這個(gè)IP 位址的同時(shí)標(biāo)記這個(gè)結(jié)果是來(lái)自於權(quán)威DNS 的結(jié)果,同時(shí)寫(xiě)入Local DNS 的解析結(jié)果緩存,這樣下一次的解析同一個(gè)網(wǎng)域就不需要做DNS 的迭代查詢了。
(2)CDN延時(shí)
一般我們會(huì)透過(guò)CDN 廠商的介面將靜態(tài)的資源寫(xiě)入到某一個(gè)CDN 節(jié)點(diǎn)上,再由CDN 內(nèi)部的同步機(jī)制將資源分散同步到每個(gè)CDN 節(jié)點(diǎn),即使CDN 內(nèi)部網(wǎng)路經(jīng)過(guò)了最佳化,這個(gè)同步的過(guò)程是有延時(shí)的,一旦我們無(wú)法從選定的CDN 節(jié)點(diǎn)上獲取到數(shù)據(jù),我們就不得不從來(lái)源站獲取數(shù)據(jù),而用戶網(wǎng)路到源站的網(wǎng)路可能會(huì)跨越多個(gè)主幹網(wǎng),這樣不僅性能上有損耗也會(huì)消耗源站的頻寬,帶來(lái)更高的研發(fā)成本。所以我們?cè)谑褂?CDN 的時(shí)候需要注意 CDN 的命中率和源站的頻寬情況。
相關(guān)學(xué)習(xí)推薦:java基礎(chǔ)
以上是java高並發(fā)系統(tǒng)設(shè)計(jì)之緩存篇的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門(mén)文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開(kāi)發(fā)環(huán)境

Dreamweaver CS6
視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版
神級(jí)程式碼編輯軟體(SublimeText3)