成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

當(dāng)我談緩存的時(shí)候,我談些什么

Lsnsh / 2951人閱讀

摘要:對(duì),當(dāng)談到緩存的時(shí)候,就是指那些設(shè)備,如瀏覽器,代理緩存服務(wù)器等。保持副本的新鮮服務(wù)器上的文本內(nèi)容隨時(shí)可能發(fā)生變化,如淘寶首頁的一個(gè)文件中需要增加記錄用戶點(diǎn)擊日志的功能,所以需要修改某個(gè)文件,以增加對(duì)應(yīng)的功能。

TL;DR

前面大段的內(nèi)容都是基本概念的介紹,建議沒時(shí)間的同學(xué)直接拖到最下面看。

Web 緩存是可以自動(dòng)保存常見文檔副本的 HTTP 設(shè)備。對(duì),當(dāng)談到緩存的時(shí)候,就是指那些設(shè)備,如瀏覽器,代理緩存服務(wù)器等。

通過網(wǎng)絡(luò)獲取內(nèi)容既緩慢,成本又高:大的響應(yīng)需要在客戶端和服務(wù)器之間進(jìn)行多次往返通信,這拖延了瀏覽器可以使用和處理內(nèi)容的時(shí)間,同時(shí)也增加了訪問者的數(shù)據(jù)成本。因此,緩存和重用以前獲取的資源的能力成為優(yōu)化性能很關(guān)鍵的一個(gè)方面。

使用緩存有下列的優(yōu)點(diǎn):

緩存減少了冗余的數(shù)據(jù)傳輸,節(jié)省了你的網(wǎng)絡(luò)費(fèi)用。

緩存緩解了網(wǎng)絡(luò)瓶頸的問題,不需要更多的帶寬就能夠更快的加載頁面。

緩存降低了對(duì)原始服務(wù)器的要求,服務(wù)器可以更快的響應(yīng),避免過載的出現(xiàn)。

緩存降低了距離時(shí)延,因?yàn)閺妮^遠(yuǎn)的地方加載頁面會(huì)更慢一些。

冗余的數(shù)據(jù)傳輸

有很多小網(wǎng)站沒有對(duì)文檔做緩存處理,這樣客戶端每次訪問相同的文檔(例如 jQuery.js)的時(shí)候,都要從服務(wù)器下載相同的文檔到本地客戶端,造成大量的冗余數(shù)據(jù)傳輸。

帶寬瓶頸

緩存會(huì)緩解有限廣域網(wǎng)絡(luò)帶寬的瓶頸問題。很多網(wǎng)絡(luò)會(huì)為本地客戶端提供的帶寬比為遠(yuǎn)程服務(wù)器提供的帶寬更寬。如果客戶端可以從一個(gè)快速局域網(wǎng)的緩存中獲得一份副本,自然可以提高性能。

瞬間擁塞

12306 的春運(yùn),微博的春晚紅包等都會(huì)遇到這種情況。12306 放票的時(shí)間段,會(huì)有大量的用戶去搶票,出現(xiàn)瞬間擁塞。瞬間擁塞可能會(huì)使網(wǎng)絡(luò)和 web 服務(wù)器發(fā)生崩潰。 DDOS 也是相同情況。

距離時(shí)延

假設(shè)淘寶的主服務(wù)器都放在杭州的一臺(tái)服務(wù)器上。而在美國的客戶端打開了淘寶,需要下載淘寶的首頁;再假設(shè)數(shù)據(jù)的傳輸都是以光速的速度傳輸。杭州到華盛頓的距離大概有14,000公里,這樣光速自身傳輸就需要大概90ms的時(shí)間(算上請(qǐng)求和返回的時(shí)間),如果淘寶頁面上只有20個(gè)圖片,這樣單連接的情況下,就大概需要(打開連接請(qǐng)求 90ms + GET web 頁面的90ms + GET 所有圖片的 90 * 20 = 1800 ms)1980ms 的時(shí)延。注意,這個(gè)只是時(shí)延。也就是說這個(gè)距離下 20 張圖片就會(huì)比客戶端在本地的請(qǐng)求延遲大概 2s 的時(shí)間。

命中和未命中的

緩存命中(cache hit) 緩存的設(shè)備(可以是代理緩存服務(wù)器,也可以是本機(jī))中有可以使用的副本。

緩存未命中(cache miss)緩存的設(shè)備中沒有可以使用的副本,這個(gè)請(qǐng)求就會(huì)被轉(zhuǎn)發(fā)給原始服務(wù)器。

保持副本的新鮮

服務(wù)器上的文本內(nèi)容隨時(shí)可能發(fā)生變化,如:淘寶首頁的一個(gè)文件中需要增加記錄用戶點(diǎn)擊日志的功能,所以需要修改某個(gè)js文件,以增加對(duì)應(yīng)的功能。對(duì)于這種情況,緩存就要不時(shí)的對(duì)其進(jìn)行檢測(cè),看看它們保存的副本是否仍是服務(wù)器上最新的副本。對(duì)于這種檢測(cè),就被稱為新鮮度檢測(cè),這些新鮮度檢測(cè)就被稱為 HTTP 再驗(yàn)證

再驗(yàn)證

為了有效的進(jìn)行再驗(yàn)證,HTTP 定義了一些特殊的請(qǐng)求,不用從服務(wù)器上獲取整個(gè)對(duì)象,就可以快速檢測(cè)出內(nèi)容是否是最新的。最常用的是 If-Modified-Since 首部(后面的內(nèi)容會(huì)提一下 ETag 和 If-None-Match)。當(dāng)這個(gè)首部被加入到 GET 請(qǐng)求中去,就可以告訴服務(wù)器:只有緩存了對(duì)象的副本之后,又對(duì)其進(jìn)行了修改的情況下,才發(fā)送此對(duì)象。

對(duì)于服務(wù)器接收到 GET If-Modified-Since 請(qǐng)求時(shí)大概會(huì)發(fā)生以下三種情況:

再驗(yàn)證命中

如果服務(wù)器對(duì)象未被修改,服務(wù)器回想客戶端發(fā)送一個(gè)小的 HTTP 304 Not Modified 響應(yīng)。

再驗(yàn)證未命中

如果服務(wù)器對(duì)象與已緩存副本不同,服務(wù)器向客戶端發(fā)送一條普通的、帶有完整內(nèi)容的 HTTP 200 OK 的響應(yīng)。

對(duì)象被刪除

如果服務(wù)器對(duì)象已經(jīng)被刪除了,服務(wù)器就會(huì)回送一個(gè) 404 Not Found 響應(yīng),緩存也會(huì)將其副本刪除。

If-Modified-Since 是 HTTP 請(qǐng)求首部,可以與 Last-Modified 服務(wù)器響應(yīng)首部配合工作。原始服務(wù)器會(huì)將最后的修改日期附加到所提供的文檔上去。當(dāng)緩存要對(duì)已緩存文檔進(jìn)行再驗(yàn)證時(shí),就會(huì)包含一個(gè) If-Modified-Since 首部,其中攜帶有最后修改已緩存副本的日期。






  hello


  
no cache
// demo1.js 

"use strict"
const http = require("http")
const fs = require("fs")

const onRequest = (req, res) => {
  const filepath = "./test.html"
  , file = fs.readFileSync(filepath)
  , stats = fs.statSync(filepath)
  , mtime = stats.mtime
  , reqMtimeString = req.headers["if-modified-since"]

  let status = 200

  if(reqMtimeString) {
    const reqMtime = new Date(reqMtimeString)
    if(reqMtime.getTime() === mtime.getTime()) status  = 304
  }

  res.writeHead(status, {"Content-Type": "text/html", "Last-Modified": mtime})
  if(200 === status) res.write(file)
  res.end()
}

http.createServer(onRequest).listen("8000", () => console.log("server start:8000"))

上面是用 Node.js 寫了一個(gè)簡(jiǎn)易的服務(wù)器,檢測(cè) test.html 是否有變化,如果最后一次修改的時(shí)間和客戶端的時(shí)間不同的話,就返回新鮮的文檔。

通過 node demo.js 運(yùn)行服務(wù)器。打開瀏覽器的開發(fā)者工具(記得把 disable cache 的選項(xiàng)勾掉),可以看到此時(shí)HTTP請(qǐng)求的 header 為:

General

Request URL:http://localhost:8000/
Request Method:GET
Status Code:200 OK
Remote Address:[::1]:8000


Response Headers

HTTP/1.1 200 OK
Content-Type: text/html
...
Last-Modified: Sat Mar 12 2016 20:03:58 GMT+0800 (CST)


Request Headers

GET / HTTP/1.1
Host: localhost:8000
...
If-Modified-Since: Sat Mar 12 2016 20:03:58 GMT+0800 (CST)

此時(shí)的返回的狀態(tài)碼為 200, 服務(wù)器設(shè)置了 Last-Modified 首部之后,瀏覽器端會(huì)加上 If-Modified-Since 的頭部。之后再刷新瀏覽器,查看開發(fā)者工具,發(fā)現(xiàn)一般頭(即 General)的 status code 變成 304 Not Modified,即上述的再驗(yàn)證命中。

再修改 test.html 的內(nèi)容:






  hello


  
change cache

刷新瀏覽器,此時(shí)的 header 如下:

General

Request URL:http://localhost:8000/
Request Method:GET
Status Code:200 OK
Remote Address:[::1]:8000


Response Headers

HTTP/1.1 200 OK
Content-Type: text/html
...
Last-Modified: Sat Mar 12 2016 20:26:36 GMT+0800 (CST)


Request Headers

GET / HTTP/1.1
Host: localhost:8000
...
If-Modified-Since: Sat Mar 12 2016 20:03:58 GMT+0800 (CST)

可以看到一般頭的 status code 又變成了 200,且響應(yīng)頭的 Last-Modified 變成最后一次修改時(shí)間,即上述的再驗(yàn)證未命中,服務(wù)器會(huì)返回修改后的文件。

對(duì)象被刪除的情況就不再寫代碼驗(yàn)證了。

文檔過期

服務(wù)器也可以通過添加一個(gè) HTTP Cache-Control 首部和 Expires 首部讓緩存可以在緩存文檔未過期的情況下隨意使用這些文檔副本。

HTTP/1.0 的 Expires 首部或 HTTP/1.1 的 Cache-Control: max-age 響應(yīng)首部來指定過期日期。Expires 使用的是絕對(duì)日期,絕對(duì)日期依賴于計(jì)算機(jī)時(shí)鐘的正確設(shè)置,如果計(jì)算機(jī)時(shí)鐘不正確,會(huì)造成緩存的過期日期不正確,可能就達(dá)不到緩存的初衷,所以在 HTTP/1.1 就增加了 Cache-Control: max-age 來替代 Expires 。

max-age 響應(yīng)首部表示的是從服務(wù)器將文檔傳來之時(shí)起,可以認(rèn)為此文檔處于新鮮狀態(tài)的秒數(shù),還有一個(gè)s-maxage的首部,其行為與 max-age 類似,僅適用于共享緩存。

服務(wù)器可以請(qǐng)求緩存不要緩存文檔(Cache-Control: no-store),或者將最大使用期設(shè)置為零(Cache-Control: max-age=0),從而在每次訪問的時(shí)候都進(jìn)行刷新。

下面是一段 Nodejs 實(shí)現(xiàn)的 max-age 代碼:

// demo2.js
"use strict"
const http = require("http")
const fs = require("fs")

const onRequest = (req, res) => {
  if("/req.js" === req.url) {
    let filepath = "./req.js"
    , file = fs.readFileSync(filepath)

    res.writeHead(200, {"Content-Type": "text/javascript", "Cache-Control": "max-age=60"})
    res.write(file)
    res.end()
  } else {
    let filepath = "./test2.html"
    , file = fs.readFileSync(filepath)

    res.writeHead(200, {"Content-Type": "text/html"})
    res.write(file)
    res.end()
  }
}

http.createServer(onRequest).listen("8000", () => console.log("server start:8000"))
// req.js
"use strict"
console.log(123)




  hello


  
no cache

打開瀏覽器,先打開開發(fā)者工具,再輸入地址之后,按回車可以看到下圖,req.js 沒有被緩存。

重新再瀏覽器輸入地址回車(手動(dòng)刷新和 cmd+r 屬于強(qiáng)制刷新,會(huì)清除緩存),可以看到下圖 req.js 已經(jīng)被緩存了(from cache):

由于在服務(wù)器上設(shè)置的緩存失效時(shí)間是 60s,所以 60s 之后再看,此時(shí)的緩存已經(jīng)失效,又會(huì)像第一幅圖一樣, req.js 沒有 from cache。

Etag 和 If-None-Match

HTTP 允許用戶對(duì) Etag 的版本標(biāo)識(shí)符進(jìn)行比較。在服務(wù)器端設(shè)置 Etag 首部之后,客戶端會(huì)對(duì)應(yīng)的生成 If-None-Match 首部。服務(wù)器端可以通過 If-None-Match 首部和對(duì)應(yīng)的文檔內(nèi)容的hash值或者其它指紋信息進(jìn)行校驗(yàn),來決定是否返回新鮮的文檔。

最優(yōu)的緩存策略

由于使用 Etag,服務(wù)器端每次都要對(duì)文檔內(nèi)容 hash 來確定是否返回新鮮的文檔,還是會(huì)浪費(fèi)大量的服務(wù)器資源,所以 Etag 的緩存策略不建議使用。

所以結(jié)合 Google 給出的最優(yōu)緩存策略,總結(jié)如下:

HTML 被標(biāo)記成no-cache,這意味著瀏覽器在每次請(qǐng)求時(shí)都會(huì)重新驗(yàn)證文檔,如果內(nèi)容更改,會(huì)獲取最新版本。同時(shí),在 HTML 標(biāo)記中,我們?cè)?CSS 和 JavaScript 資源的網(wǎng)址中嵌入指紋碼:如果這些文件的內(nèi)容更改,網(wǎng)頁的 HTML 也會(huì)隨之更改,并將下載 HTML 響應(yīng)的新副本。

允許瀏覽器和中繼緩存(例如 CDN)緩存 CSS,過期時(shí)間設(shè)置為 1 年。注意,我們可以放心地使用 1 年的’遠(yuǎn)期過期’,因?yàn)槲覀冊(cè)谖募星度肓宋募讣y碼:如果 CSS 更新,網(wǎng)址也會(huì)隨之更改。

JavaScript 過期時(shí)間也設(shè)置為 1 年,但是被標(biāo)記為 private,也許是因?yàn)榘?CDN 不應(yīng)緩存的一些用戶私人數(shù)據(jù)。

緩存圖片過期時(shí)間盡量設(shè)置超長(zhǎng)。

上面第一條所說的指紋碼一般是指文檔內(nèi)容的 hash 值,這個(gè)可以通過 gulp,webpack 等打包工具在生成文件的時(shí)候就生出 hash 值,附在文件名后面,例如:jquery.min.js,根據(jù)文檔生成的 hash 值為 1iuiqe981823,文件名可以自動(dòng)生成為: jquery.min.1iuiqe981823.js。這樣既可以保證在文檔沒有變化是可以從緩存中讀取,又可以保證文檔在有變化可以及時(shí)更新。

最后

本文大部分內(nèi)容都是直接引用『HTTP 權(quán)威指南』,最后一部分的最優(yōu)策略是參考 Google Developers 的文檔。有些許內(nèi)容是理解之后給出的代碼實(shí)現(xiàn)或驗(yàn)證。

原文

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/61783.html

相關(guān)文章

  • 當(dāng)我談Proxy與Adpater模式時(shí),我談什么

    摘要:適配器模式屬于兩種適應(yīng)設(shè)計(jì)模式中的其中一種,另外一種是迭代器模式,下次有機(jī)會(huì)再仔細(xì)聊聊它。設(shè)計(jì)模式的書很喜歡以電源適配器插頭作為適配器模式的范例范例,那么我們也從這個(gè)例子開始吧。 當(dāng)我談Proxy與Adpater模式時(shí),我談些什么 前言 今天跟同事談起了一道面試題:Proxy模式跟Adpater模式的區(qū)別,這兩個(gè)設(shè)計(jì)模式都是很相似的模式,很多有點(diǎn)經(jīng)驗(yàn)的程序員都可能會(huì)聊的頭頭是道,但是恐...

    incredible 評(píng)論0 收藏0
  • 當(dāng)我談vim映射時(shí),我談什么

    摘要:注意不僅能映射單個(gè)鍵,還能映射一組鍵,比如臉滾鍵盤。通過命令可以顯示當(dāng)前鍵映射的情況。表示不允許映射的結(jié)果參與其他的映射規(guī)則的匹配。當(dāng)然也有用武之地,比如當(dāng)你需要映射的結(jié)果來觸發(fā)另一個(gè)映射時(shí),就用得上了。 映射功能是當(dāng)下各大編輯器的標(biāo)配,如果你想要熟悉所用的編輯器,必然不能缺少對(duì)它的映射機(jī)制的學(xué)習(xí)。對(duì)于vim亦是如此。 這里說到的映射功能,指的是編輯器會(huì)捕獲用戶的輸入,并且按照事先的...

    GHOST_349178 評(píng)論0 收藏0
  • lodash源碼分析之自減兩種形式

    摘要:作用與用法是的內(nèi)部函數(shù),之前在源碼分析之緩存介紹過一種這樣的數(shù)據(jù)結(jié)構(gòu)這是一個(gè)二維數(shù)組,每項(xiàng)中的第一項(xiàng)作為緩存對(duì)象的,第二項(xiàng)為緩存的值。 這個(gè)世界需要一個(gè)特定的惡人,可以供人們指名道姓,千夫所指:全都怪你?!迳洗簶洹懂?dāng)我談跑步時(shí)我談些什么》 本文為讀 lodash 源碼的第六篇,后續(xù)文章會(huì)更新到這個(gè)倉庫中,歡迎 star:pocket-lodash gitbook也會(huì)同步倉庫的更新...

    Keven 評(píng)論0 收藏0
  • 當(dāng)談?wù)摰鲿r(shí),我談什么?

    摘要:示例代碼如下此示例中可以看出,當(dāng)?shù)鹘K止時(shí),通過拋出異常告知迭代器已耗盡。但如果迭代器所指向的數(shù)據(jù)結(jié)構(gòu)在其存在時(shí)發(fā)生了插入或刪除操作,則迭代器將可能失效。與的情形類似,對(duì)進(jìn)行任何插入操作也將損壞迭代器。 花下貓語:之前說過,我對(duì)于編程語言跟其它學(xué)科的融合非常感興趣,但我還說漏了一點(diǎn),就是我對(duì)于 Python 跟其它編程語言的對(duì)比學(xué)習(xí),也很感興趣。所以,我一直希望能聚集一些有其它語言基...

    王軍 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Lsnsh

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<