首先我畫了一個粗糙的圖形,用來表示咱們使用web請求所經歷的過程。你們將就看下html
從圖能夠看出,當用戶發起一個網絡請求。首先會通過瀏覽器的緩存,而後通過靜態資源的CDN緩存,而後是Nginx等反向代理緩存,再是web緩存,最後還有數據庫緩存。下面咱們一一來看。前端
http協議有本身的緩存協商機制。 react
對於http1.0 使用的是基於iso-time的 expired響應頭去判斷資源過時與否。 webpack
http1.1使用三種web
1.是基於修改精確時間的Last-Modifieredis
2基於文件相對時間的max-age(這個資源你能夠用多久)spring
from cache 是沒有和服務器確認,通常是運維去除了e-tag或者說是使用了長緩存數據庫
3.基於文件內容hash的 e-tag瀏覽器
另一方面,能夠把緩存分紅三種策略,分別是存儲策略,協商策略和過時策略。緩存
last-modify , eTag屬於協商策略,協商策略用於從新驗證緩存資源是否有效, 須要發一次http請求,用於判斷當前的緩存資源是否有效。 強緩存只有cache-control(http1.1) 和 pragma(http1.0)的 max-age等策略命中。 也就是說last-modify , eTag 這種協商緩存並不會減小http請求,而是減小了請求時間和字節數。
對於http1.0 的 Expires 實際上是過時策略,用於判斷當前瀏覽器存儲的緩存是否過時,Pragma指定緩存機制. http1.0 已經淘汰,僅供瞭解
cache-control 指定緩存機制,須要單獨看待,他能夠覆蓋其餘header的值,何解?
語法爲: "Cache-Control : cache-directive".
Cache-directive共有以下12種(其中請求中指令7種, 響應中指令9種):
Cache-directive | 描述 | 存儲策略 | 過時策略 | 請求字段 | 響應字段 |
---|---|---|---|---|---|
public | 資源將被客戶端和代理服務器緩存 | ✔️ | ✔️ | ||
private | 資源僅被客戶端緩存, 代理服務器不緩存 | ✔️ | ✔️ | ||
no-store | 請求和響應都不緩存 | ✔️ | ✔️ | ✔️ | |
no-cache | 至關於max-age:0,must-revalidate 即資源被緩存, 可是緩存馬上過時, 同時下次訪問時強制驗證資源有效性 |
✔️ | ✔️ | ✔️ | ✔️ |
max-age | 緩存資源, 可是在指定時間(單位爲秒)後緩存過時 | ✔️ | ✔️ | ✔️ | ✔️ |
s-maxage | 同上, 依賴public設置, 覆蓋max-age, 且只在代理服務器上有效. | ✔️ | ✔️ | ✔️ | |
max-stale | 指定時間內, 即便緩存過期, 資源依然有效 | ✔️ | ✔️ | ||
min-fresh | 緩存的資源至少要保持指定時間的新鮮期 | ✔️ | ✔️ | ||
must-revalidation /proxy-revalidation | 若是緩存失效, 強制從新向服務器(或代理)發起驗證(由於max-stale等字段可能改變緩存的失效時間) | ✔️ | ✔️ | ||
only-if-cached | 僅僅返回已經緩存的資源, 不訪問網絡, 若無緩存則返回504 | ✔️ | |||
no-transform | 強制要求代理服務器不要對資源進行轉換, 禁止代理服務器對Content-Encoding ,Content-Range ,Content-Type 字段的修改(所以代理的gzip壓縮將不被容許) |
✔️ | ✔️ |
CND是爲了避免同的網絡環境均可以得到一致的高速體驗而服務的。將一些靜態資源放在cdn可使用戶訪問這個靜態資源的時候選擇網絡狀態最好的。合理使用cdn能夠大大提升訪問速度。可是cdn也有很麻煩的地方,就是發佈的時候,瀏覽器緩存可能讀取的是舊版本的,這時候傳統方法是使用query,可是query也有不少問題,文件發佈順序啥的會影響,並且須要手工加入版本號。 這裏推薦webpack build 加hash。 咱們目前是使用的webpack 插件 webpack-html-plugin
這裏說的是反向代理(我以爲叫服務端代理可能更容易理解)反向代理有保護服務器安全(將外部請求轉發給內部服務器,同時將內部服務器響應轉發給Client),緩存加速和實現負載均衡的做用。如今咱們的站點測試環境使用的是Nginx1.8.x 。而生產環境使用的是淘寶Tengineer
咱們系統使用的tomcat服務器,因此在這裏講一下tomcat服務器的緩存策略。
tomcat默認是隻對靜態組員進行緩存對jsp是不緩存的。當前端發送一個請求時,服務端會根據這個資源的特徵進行不一樣的緩存策略。 本質上是存到一個map中,將etag或者last-modified做爲value(前面講瀏覽器緩存有說過),將資源的url做爲一個key存儲,當資源發生變化的時候咱們去更新這個map的value,當下次資源被請求會比較etag或者last-modified是否是最新的數據,若是是返回304.不是的話返回200和對應內容
tomcat源碼中的!checkIfHeaders(request, response, cacheEntry.attributes)) 是整個機制的核心,用來判斷資源是否須要從新獲取,返回false就從新獲取
protected boolean checkIfHeaders(HttpServletRequest request,
HttpServletResponse response,
ResourceAttributes resourceAttributes)
throws IOException {
return checkIfMatch(request, response, resourceAttributes)
&& checkIfModifiedSince(request, response, resourceAttributes)
&& checkIfNoneMatch(request, response, resourceAttributes)
&& checkIfUnmodifiedSince(request, response, resourceAttributes);
}
這裏四個check都返回true(都認爲資源被改變了),那麼checkIfHeaders久返回true,對應就要從新獲取而不走緩存
在這裏使用memcached大大緩解了數據庫的讀壓力,固然對於寫仍是會形成負擔的(更新數據, 須要同時更新數據庫和緩存),好在大部分應用都是讀遠大於寫,使用simple spring memcached大大簡化了緩存配置,ssm在key生成規則和list緩存上作的很好。有時間我也會進一步瞭解下。
環境:reflux + react
使用react-router-loader實現按需打包加載運用在SPA必定程度解決了單頁應用程序性能問題。使用後基本上每一個頁面初次訪問都在200kb~300kb,並且靜態資源能夠獲得緩存。但如今存在一個問題就是用戶在多頁面切換的時候回發送不少請求。以個人頁面爲例,每次要發送6個請求。可能就有600-700ms延遲。下圖是切換三次頁面的網絡請求結果
在這裏我打算作一次代碼緩存,也就說只有第一次加載我從服務器拿,其餘時候我是從code cache中拿。 只有用戶強制刷新頁面纔去後臺拿數據。
首先將cache掛載到store上,這裏利用了Store單例的特性,即應用只有一份數據,這樣不會出現髒數據的狀況,而後get以前判斷緩存中有沒有,若是有直接返回,不然發送一個網絡請求
若是請求成功,而且緩存不存在就添加緩存(第一次請求緩存是不存在的)。若是存在緩存不作處理。
直接在請求成功後的回調方法中更新對應緩存。
能夠看下效果
博客不能夠上傳視頻,悲哀啊。那就圖片吧。
看下優化後的結果:
只有第一次請求會加載6次之後都是不會請求的
[瀏覽器緩存機制剖析](https://juejin.im/post/58eacff90ce4630058668257)