隨筆——緩存系列開篇

跨過了2019來到了2020年,新年新氣象,準備寫一些系列性質的文章,旨在更好的對知識概括總結,更系統的理解一塊知識面。好的廢話很少說,2020年開篇的主題是緩存系列,是個程序員或多或少都跟緩存打過交道,做爲一個Java程序員大部分時候仍是在應用層使用緩存,接觸的緩存框架和中間件會比較多,可是本系列並不想僅限於應用層講述緩存,我將從底層到CPU、操做系統,中層到瀏覽器、CDN,上層應用程序來說述緩存的應用,經過這個系列能學習到緩存的應用場景及時機。css

前言

新的一年我將稍微改變一下本身的文章排布,將複雜的問題做爲一個系列分塊講述,提取模塊的重點並減小單篇文章的篇幅,下降閱讀時間。本篇文章做爲緩存系列的開篇之做第一步天然是挖坑,本系列將從如下幾個方面分多篇文章來說述緩存。html

  1. 緩存系列開篇——緩存定義、瀏覽器、CDN中的緩存
  2. 緩存系列二——操做系統、CPU中的緩存
  3. 緩存系列三——應用程序中的緩存
  4. 緩存系列四——常見的緩存中間件
  5. 緩存系列五——緩存常見問題與總結

什麼是緩存

關於定義你去搜索wiki、百度百科就會發現給出來的都是跟存儲器相關的,這其實不是我想要的答案。node

我認爲的緩存是一個抽象的概念,它能夠是一個存儲器、一個應用程序或者一個服務器,但無論它是什麼東西,它的行爲永遠都是保存一份原始資源的副本並提供一個高速的訪問途徑,而有這個行爲的任意東西均可以稱之爲緩存。nginx

知道緩存的定義後它的應用場景也就很清楚了,當你有頻繁讀取的需求,且源數據訪問速度遠低於本地訪問時,可採用緩存的解決方案。程序員

瀏覽器中的緩存

爲什麼使用緩存

要知道瀏覽器爲什麼使用緩存咱們就得知道咱們使用瀏覽器打開一個網頁時,瀏覽器作了什麼?算法

一個網頁是由HTML+JS+CSS+靜態文件組成的,當咱們使用瀏覽器打開一個網頁時,瀏覽器實際上是在訪問Web服務器的HTMLJSCSS、靜態文件(如圖片、gif)等資源,作過Web開發的都知道JSCSS以及靜態文件在網站上線後基本不會改變,HTML做爲網頁結構若是是服務端渲染那麼它是可變的。瀏覽器

結合這些知道再看看咱們上面提到的緩存應用場景緩存

  1. 瀏覽器做爲一個網頁客戶端,天然會有頻繁請求網頁的需求,即頻繁讀取Web服務器的資源
  2. 瀏覽器訪問Web服務器的速度確定比訪問本地的速度慢一個量級

因而瀏覽器就採用了本地緩存服務器資源的方式來減小發往服務器的請求,也提升了頁面加載的效率,在用戶使用時也會感覺到第一次打開頁面的時候有點慢,後面就快了不少。服務器

這裏會有一個問題,瀏覽器不能緩存全部數據,這樣會致使你網頁從新發布了可是客戶瀏覽器的網頁確一直不更新,因此瀏覽器須要根據服務器的安排來緩存數據。網絡

如何使用瀏覽器緩存

服務器如何控制瀏覽器的緩存呢?這就得講講HTTP協議了,由於瀏覽器獲取服務器資源都是經過此協議進行交互訪問。爲了更好的講述瀏覽器緩存流程我截取了本人博客網站的一個CSS資源的響應體以下

Request URL: https://chenjianhui.site/css/back-to-top.css
Request Method: GET
Status Code: 200 OK (from disk cache)
Remote Address: 120.79.79.226:443
Referrer Policy: no-referrer-when-downgrade
Accept-Ranges: bytes
Content-Length: 343
Content-Type: text/css
Date: Tue, 07 Jan 2020 02:19:37 GMT
ETag: "5e0aac7c-157"
Last-Modified: Tue, 31 Dec 2019 02:03:40 GMT
Server: nginx/1.15.12
Referer: https://chenjianhui.site/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36

CSS Content ...
複製代碼

重點關注如下幾個響應頭部信息,這部分頭部實現了協商緩存

  • Status Code:請求響應碼,這裏200表明成功,後面還有一個括號from disk cache描述了這個資源來自於本地磁盤的緩存。
  • ETag:資源的特定版本的標識符,相似於資源的指紋(Hash值),用於提供給瀏覽器快速肯定資源是否變化。
  • Last-Modified:資源作出修改的日期及時間,一般被用做一個驗證器來判斷接收到的或者存儲的資源是否彼此一致,因爲精確度比ETag要低,因此這是一個備用機制。包含有If-Modified-SinceIf-Unmodified-Since首部的條件請求會使用這個字段。

那麼整個網絡請求的流程是怎樣的呢?

  1. 客戶端get請求資源,服務器返回資源,並在響應頭中帶上了ETagLast-Modified的值,此時客戶端將資源緩存在本地。
  2. 客戶端再次請求這個資源,在啓用緩存的狀況下,將上次請求的ETag屬性值做爲If-None-Match的值,Last-Modified的值做爲If-Modified-Since隨請求頭髮給服務器。
  3. 服務器判斷資源現有的ETagIf-None-Match的值是否相等,若是相等,會返回304和空的響應體。瀏覽器根據304取本地緩存。

這就是瀏覽器緩存的所有了嗎? 固然不是,還有兩個響應頭部是用於瀏覽器緩存的,它們稱之爲強制緩存,分別是

  • Expires: 響應頭包含日期/時間,即在此時候以後,響應過時。若是是無效的日期表明資源已通過期。
  • Cache-Control:經過指定指令來實現緩存機制,緩存指令是單向的。好比Cache-Control: max-age=30表明該資源能夠緩存的30秒,max-age的優先級將高於Expires

實踐瀏覽器緩存

在知道了緩存頭部的做用後,咱們能夠寫一些代碼來實踐一下讓瀏覽器緩存咱們的數據。

因爲使用Java代碼啓動一個HTTP服務器還須要通過編譯過程太過麻煩,所以這裏採用Nodejs來實現緩存示例

const PORT = 3030;
const CACHE_SECONDS = 10;
// 加載http模塊
var http = require('http');
// 建立http服務器
var server = http.createServer(function (req, res) {
  if (req.url === '/test.js') {
    // 設置緩存響應頭部
    res.setHeader('Cache-Control', `max-age=${CACHE_SECONDS}, public`);
    res.end(`document.body.append('Load script test.js on ${new Date()}')`)
  } else {
    // 首頁加載 test.js 腳本
    res.end(`<html><body><h1>Script will cache ${CACHE_SECONDS} seconds</h1></body><script src="http://localhost:${PORT}/test.js"></script></html>`);
  }
})
server.listen(PORT)
console.log(`Listening in http://localhost:${PORT}`)
複製代碼

這段代碼能夠拷貝到有Nodejs環境的機器中使用node xxx.js直接運行,它主要作了如下幾件事情:

  1. 監聽3030端口啓動了一個HTTP服務器,默認提供了一個HTML頁面,該頁面經過script標籤加載了test.js腳本。
  2. 當訪問test.js腳本時設置了Cache-Control: max-age=10, public響應頭部,即容許瀏覽器緩存該資源10秒。
  3. test.js腳本向頁面寫入了一行字符串,該字符串包含了服務器響應腳本的時間new Date()

如今咱們經過瀏覽器測試一下緩存頭部是否生效,運行腳本文件後在瀏覽器打開http://localhost:3030以下圖所示。

能夠看到這裏顯示加載腳本的時間是14:12:13,如今咱們十秒內刷新一下頁面,運行效果以下圖。

這裏能夠看到顯示效果上沒有改變,可是網絡監控方面顯示腳本是從緩存中獲取(from memory cache),如今咱們靜候一段時間再點擊刷新,腳本緩存失效從新從服務器上獲取了最新資源,時間變成了14:12:45,運行效果以下圖。

有關其餘的緩存頭部能夠根據相同的方式進行測試,多動手對本身理解這些HTTP響應頭部以及協議會有很大的幫助。

CDN中的緩存

爲何CDN緩存要和瀏覽器緩存放一塊兒說呢?由於它們都是爲了提升網頁訪問速度而設計的。瀏覽器緩存是提升了頻繁請求資源的速度,CDN緩存提升了單次請求資源的速度。

CDN是什麼

CDN是Content Delivery Network的簡稱,即「內容分發網絡」的意思。通常咱們所說的CDN加速,通常是指網站加速或者用戶下載資源加速。

那麼它如何作到加速效果呢?

就近訪問原則,就如同你找水電燃氣的繳費點,因爲各個繳費點提供的服務是同樣的,你確定會選擇離你最近的服務點進行繳費。同理在訪問網頁時咱們也能夠根據客戶機的位置,爲它選擇一個最近的服務節點提供資源服務,尋找最近服務節點的這個過程就叫作CDN加速。

CDN工做原理

瞭解CDN的工做原理以前咱們先來看看傳統網站的訪問過程

  1. 瀏覽器輸入chenjianhui.site
  2. 瀏覽器請求DNS服務器,查詢到chenjianhui.site對應服務器的IP
  3. 向該服務器發起HTTP請求獲得網頁、加載其餘內容、渲染頁面等等(這裏簡略了一些東西、好比咱們上面聊到的瀏覽器緩存)

這裏須要重點講一下第2步,由於CND就是在這一步作了文章,其具體過程以下所示:

  • chenjianhui.site解析成IP的具體過程
    1. 操做系統查詢本地緩存(host文件或者是瀏覽器的緩存)是否有解析記錄,有則直接使用,沒有則進入第2步
    2. 操做系統向LocalDNS查詢域名的IP地址,通常稱運營商的DNS服務器爲LocalDNS,這裏LocalDNS會先查詢本地緩存,沒有則進入第3步
    3. LocalDNSRootDNS查詢獲得權威服務器,傳說中全球只有幾臺的那些服務器稱之爲RootDNS
    4. LocalDNS向權威服務器查詢IP地址,緩存這個地址並將結果返回給客戶端

CDN其實就是做用於域名解析的第4步,傳統的網站第4步是返回一個IP地址,而加入CDN後這裏通常返回一個CNAME記錄

這裏要補充一個知識點,常見的DNS解析記錄有A,AAAA,CNAME等等,其中

  • A記錄是域名到IPV4地址的
  • AAAA記錄是域名到IPV6地址的
  • CNAME記錄是域名到域名的,即你去問問這個域名,他知道該解析成什麼
  1. LocalDns獲得一個CNAME記錄,向智能調度DNS查詢域名的ip地址
  2. 智能調度DNS 根據必定的算法和策略(好比靜態拓撲,容量等),將最適合的CDN節點IP地址迴應給LocalDns

參考資料

關於公衆號

相關文章
相關標籤/搜索