国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

當我談緩存的時候,我談些什么

Lsnsh / 2947人閱讀

摘要:對,當談到緩存的時候,就是指那些設備,如瀏覽器,代理緩存服務器等。保持副本的新鮮服務器上的文本內容隨時可能發生變化,如淘寶首頁的一個文件中需要增加記錄用戶點擊日志的功能,所以需要修改某個文件,以增加對應的功能。

TL;DR

前面大段的內容都是基本概念的介紹,建議沒時間的同學直接拖到最下面看。

Web 緩存是可以自動保存常見文檔副本的 HTTP 設備。對,當談到緩存的時候,就是指那些設備,如瀏覽器,代理緩存服務器等。

通過網絡獲取內容既緩慢,成本又高:大的響應需要在客戶端和服務器之間進行多次往返通信,這拖延了瀏覽器可以使用和處理內容的時間,同時也增加了訪問者的數據成本。因此,緩存和重用以前獲取的資源的能力成為優化性能很關鍵的一個方面。

使用緩存有下列的優點:

緩存減少了冗余的數據傳輸,節省了你的網絡費用。

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

緩存降低了對原始服務器的要求,服務器可以更快的響應,避免過載的出現。

緩存降低了距離時延,因為從較遠的地方加載頁面會更慢一些。

冗余的數據傳輸

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

帶寬瓶頸

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

瞬間擁塞

12306 的春運,微博的春晚紅包等都會遇到這種情況。12306 放票的時間段,會有大量的用戶去搶票,出現瞬間擁塞。瞬間擁塞可能會使網絡和 web 服務器發生崩潰。 DDOS 也是相同情況。

距離時延

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

命中和未命中的

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

緩存未命中(cache miss)緩存的設備中沒有可以使用的副本,這個請求就會被轉發給原始服務器。

保持副本的新鮮

服務器上的文本內容隨時可能發生變化,如:淘寶首頁的一個文件中需要增加記錄用戶點擊日志的功能,所以需要修改某個js文件,以增加對應的功能。對于這種情況,緩存就要不時的對其進行檢測,看看它們保存的副本是否仍是服務器上最新的副本。對于這種檢測,就被稱為新鮮度檢測,這些新鮮度檢測就被稱為 HTTP 再驗證

再驗證

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

對于服務器接收到 GET If-Modified-Since 請求時大概會發生以下三種情況:

再驗證命中

如果服務器對象未被修改,服務器回想客戶端發送一個小的 HTTP 304 Not Modified 響應。

再驗證未命中

如果服務器對象與已緩存副本不同,服務器向客戶端發送一條普通的、帶有完整內容的 HTTP 200 OK 的響應。

對象被刪除

如果服務器對象已經被刪除了,服務器就會回送一個 404 Not Found 響應,緩存也會將其副本刪除。

If-Modified-Since 是 HTTP 請求首部,可以與 Last-Modified 服務器響應首部配合工作。原始服務器會將最后的修改日期附加到所提供的文檔上去。當緩存要對已緩存文檔進行再驗證時,就會包含一個 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 寫了一個簡易的服務器,檢測 test.html 是否有變化,如果最后一次修改的時間和客戶端的時間不同的話,就返回新鮮的文檔。

通過 node demo.js 運行服務器。打開瀏覽器的開發者工具(記得把 disable cache 的選項勾掉),可以看到此時HTTP請求的 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)

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

再修改 test.html 的內容:






  hello


  
change cache

刷新瀏覽器,此時的 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,且響應頭的 Last-Modified 變成最后一次修改時間,即上述的再驗證未命中,服務器會返回修改后的文件。

對象被刪除的情況就不再寫代碼驗證了。

文檔過期

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

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

max-age 響應首部表示的是從服務器將文檔傳來之時起,可以認為此文檔處于新鮮狀態的秒數,還有一個s-maxage的首部,其行為與 max-age 類似,僅適用于共享緩存。

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

下面是一段 Nodejs 實現的 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

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

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

由于在服務器上設置的緩存失效時間是 60s,所以 60s 之后再看,此時的緩存已經失效,又會像第一幅圖一樣, req.js 沒有 from cache。

Etag 和 If-None-Match

HTTP 允許用戶對 Etag 的版本標識符進行比較。在服務器端設置 Etag 首部之后,客戶端會對應的生成 If-None-Match 首部。服務器端可以通過 If-None-Match 首部和對應的文檔內容的hash值或者其它指紋信息進行校驗,來決定是否返回新鮮的文檔。

最優的緩存策略

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

所以結合 Google 給出的最優緩存策略,總結如下:

HTML 被標記成no-cache,這意味著瀏覽器在每次請求時都會重新驗證文檔,如果內容更改,會獲取最新版本。同時,在 HTML 標記中,我們在 CSS 和 JavaScript 資源的網址中嵌入指紋碼:如果這些文件的內容更改,網頁的 HTML 也會隨之更改,并將下載 HTML 響應的新副本。

允許瀏覽器和中繼緩存(例如 CDN)緩存 CSS,過期時間設置為 1 年。注意,我們可以放心地使用 1 年的’遠期過期’,因為我們在文件名中嵌入了文件指紋碼:如果 CSS 更新,網址也會隨之更改。

JavaScript 過期時間也設置為 1 年,但是被標記為 private,也許是因為包含了 CDN 不應緩存的一些用戶私人數據。

緩存圖片過期時間盡量設置超長。

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

最后

本文大部分內容都是直接引用『HTTP 權威指南』,最后一部分的最優策略是參考 Google Developers 的文檔。有些許內容是理解之后給出的代碼實現或驗證。

原文

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/61783.html

相關文章

  • 我談Proxy與Adpater模式時,我談什么

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

    incredible 評論0 收藏0
  • 我談vim映射時,我談什么

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

    GHOST_349178 評論0 收藏0
  • lodash源碼分析之自減兩種形式

    摘要:作用與用法是的內部函數,之前在源碼分析之緩存介紹過一種這樣的數據結構這是一個二維數組,每項中的第一項作為緩存對象的,第二項為緩存的值。 這個世界需要一個特定的惡人,可以供人們指名道姓,千夫所指:全都怪你。——村上春樹《當我談跑步時我談些什么》 本文為讀 lodash 源碼的第六篇,后續文章會更新到這個倉庫中,歡迎 star:pocket-lodash gitbook也會同步倉庫的更新...

    Keven 評論0 收藏0
  • 當談論迭代器時,我談什么

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

    王軍 評論0 收藏0

發表評論

0條評論

Lsnsh

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<