客戶端緩存技術
java緩存技術
一、什麼是緩存
1、Cache是高速緩沖存儲器 一種特殊的存儲器子系統,其中復制了頻繁使用的數據以利於快速訪問
2、凡是位於速度相差較大的兩種硬體/軟體之間的,用於協調兩者數據傳輸速度差異的結構,均可稱之為 Cache
二、緩存的分類
1、基於web應用的系統架構圖
2、在系統架構的不同層級之間,為了加快訪問速度,都可以存在緩存
操作系統磁碟緩存->減少磁碟機械操作
資料庫緩存->減少文件系統I/O
應用程序緩存->減少對資料庫的查詢
Web伺服器緩存->減少應用伺服器請求
客戶端瀏覽器緩存->減少對網站的訪問。
B. 常用的緩存技術
第一章 常用的緩存技術
1、常見的兩種緩存
本地緩存:不需要序列化,速度快,緩存的數量與大小受限於本機內存
分布式緩存:需要序列化,速度相較於本地緩存較慢,但是理論上緩存的數量與大小無限(因為緩存機器可以不斷擴展)
2、本地緩存
Google guava cache:當下最好用的本地緩存
Ehcache:spring默認集成的一個緩存,以spring cache的底層緩存實現類形式去操作緩存的話,非常方便,但是欠缺靈活,如果想要靈活使用,還是要單獨使用Ehcache
Oscache:最經典簡單的頁面緩存
3、分布式緩存
memcached:分布式緩存的標配
Redis:新一代的分布式緩存,有替代memcached的趨勢
3.1、memcached
經典的一致性hash演算法
基於slab的內存模型有效防止內存碎片的產生(但同時也需要估計好啟動參數,否則會浪費很多的內存)
集群中機器之間互不通信(相較於Jboss cache等集群中機器之間的相互通信的緩存,速度更快<--因為少了同步更新緩存的開銷,且更適合於大型分布式系統中使用)
使用方便(這一點是相較於Redis在構建客戶端的時候而言的,盡管redis的使用也不困難)
很專一(專做緩存,這一點也是相較於Redis而言的)
3.2、Redis
可以存儲復雜的數據結構(5種)
strings-->即簡單的key-value,就是memcached可以存儲的唯一的一種形式,接下來的四種是memcached不能直接存儲的四種格式(當然理論上可以先將下面的一些數據結構中的東西封裝成對象,然後存入memcached,但是不推薦將大對象存入memcached,因為memcached的單一value的最大存儲為1M,可能即使採用了壓縮演算法也不夠,即使夠,可能存取的效率也不高,而redis的value最大為1G)
hashs-->看做hashTable
lists-->看做LinkedList
sets-->看做hashSet,事實上底層是一個hashTable
sorted sets-->底層是一個skipList
有兩種方式可以對緩存數據進行持久化
RDB
AOF
事件調度
發布訂閱等
4、集成緩存
專指spring cache,spring cache自己繼承了ehcache作為了緩存的實現類,我們也可以使用guava cache、memcached、redis自己來實現spring cache的底層。當然,spring cache可以根據實現類來將緩存存在本地還是存在遠程機器上。
5、頁面緩存
在使用jsp的時候,我們會將一些復雜的頁面使用Oscache進行頁面緩存,使用非常簡單,就是幾個標簽的事兒;但是,現在一般的企業,前台都會使用velocity、freemaker這兩種模板引擎,本身速度就已經很快了,頁面緩存使用的也就很少了。
總結:
在實際生產中,我們通常會使用guava cache做本地緩存+redis做分布式緩存+spring cache就集成緩存(底層使用redis來實現)的形式
guava cache使用在更快的獲取緩存數據,同時緩存的數據量並不大的情況
spring cache集成緩存是為了簡單便捷的去使用緩存(以註解的方式即可),使用redis做其實現類是為了可以存更多的數據在機器上
redis緩存單獨使用是為了彌補spring cache集成緩存的不靈活
就我個人而言,如果需要使用分布式緩存,那麼首先redis是必選的,因為在實際開發中,我們會緩存各種各樣的數據類型,在使用了redis的同時,memcached就完全可以舍棄了,但是現在還有很多公司在同時使用memcached和redis兩種緩存。
C. 優酷客戶端怎麼緩存
1、優酷視頻上緩存,首先要在客戶端上播放需要緩存的視頻。
D. 瀏覽器緩存和伺服器緩存
一、瀏覽器緩存
瀏覽器緩存即http緩存;瀏覽器緩存根據是否需要向伺服器重新發起HTTP請求將緩存過程分為兩個部分,分別是 強制緩存 和 協商緩存 。
瀏覽器第一次請求資源的時候伺服器會告訴客戶端是否應該緩存資源,根據響應報文中HTTP頭的緩存標識,決定是否緩存結果,是則將請求結果和緩存標識存入瀏覽器緩存中。如下圖:
1.強制緩存 :瀏覽器會對緩存進行查找,並根據一定的規則確定是否使用緩存。
強制緩存的緩存規則?
HTTP/1.0 Expires 這個欄位是絕對時間,比如2018年6月30日12:30,然後在這個時間點之前的請求都會使用瀏覽器緩存,除非清除了緩存。
這個欄位的缺點就是只會同步客戶端的時間,這就有可能修改客戶端時間導致緩存失效。
HTTP/1.1 cache-Control 這個是1.1的時候替換Expires的,它會有幾種取值:
public :所有內容都將被緩存(客戶端和代理伺服器都可緩存)
private :所有內容只有客戶端可以緩存, Cache-Control的默認取值
no-cache :客戶端緩存內容,但是是否使用緩存則需要經過協商緩存來驗證決定
no-store :所有內容都不會被緩存,即不使用強制緩存,也不使用協商緩存
max-age=xxx (xxx is numeric) :緩存內容將在xxx秒後失效
比如max-age=500,則在500秒內再次請求會直接只用緩存。
優先性:cache-Control > Expires
如果同時存在,cache-Control會覆蓋Expires。
這個欄位的缺點就是:
如果資源更新的速度是秒以下單位,那麼該緩存是不能被使用的,因為它的時間單位最低是秒。
如果文件是通過伺服器動態生成的,那麼該方法的更新時間永遠是生成的時間,盡管文件可能沒有變化,所以起不到緩存的作用。
上圖中瀏覽器緩存中存在該資源的緩存結果,並且沒有失效,就會直接使用緩存的內容。
上圖中瀏覽器緩存中沒有該資源的緩存結果和標識,就會直接向伺服器發起HTTP請求。
2.協商緩存: 瀏覽器的強制緩存失效後(時間過期),瀏覽器攜帶緩存標識請求伺服器,由伺服器決定是否使用緩存。
伺服器決定的規則?
控制協商緩存的欄位有 Last-Modified / If-Modified-Since 和 Etag / If-None-Match。
①Last-Modified 是伺服器返回給瀏覽器的本資源的最後修改時間。
當下次再次請求的時候,瀏覽器會在請求頭中帶 If-Modified-Since ,即上次請求下來的 Last-Modified 的值,
然後伺服器會用這個值和該資源最後修改的時間比較,如果最後修改時間大於這個值,則會重新請求該資源,返回狀態碼200。
如果這個值和最後修改時間相等,則會返回304,告訴瀏覽器繼續使用緩存。
② Etag 是伺服器返回的一個hash值。
當下次再次請求的時候,瀏覽器會在請求頭中帶 If-None-Match ,即上次請求下來的 Etag 值,
然後伺服器會用這個值和該資源在伺服器的 Etag 值比較,如果一致則會返回304,繼續使用緩存;如果不一致,則會重新請求,返回200。
二、伺服器緩存
上面是一個簡單的流程圖:
用戶1訪問A頁面,伺服器解析A頁面返回給用戶1,同時在伺服器內存上做一定映射,把A頁面緩存在硬碟上面
用戶2訪問A頁面,伺服器直接根據內存上的映射找到對應的頁面緩存,直接返回給用戶2,這樣就減少了伺服器對同一頁面的重復解析
伺服器緩存和瀏覽器緩存的區別:
伺服器緩存是把頁面緩存到伺服器上的硬碟里,而瀏覽器緩存是把頁面緩存到用戶自己的電腦里
Nginx伺服器
Nginx是一個高性能的HTTP和反向代理伺服器。具有非常多的優越性:
在連接高並發的情況下,Nginx是Apache伺服器不錯的替代品,Nginx在美國是做虛擬主機生意的老闆們經常選擇的軟體平台之一。
Nginx提供了expires、etag、if-modified-since指令來實現瀏覽器緩存控制。
nginx -s reload#重新載入配置文件
nginx -s reopen#重新打開log文件
nginx -s stop#快速關閉nginx服務
nginx -s quit #優雅的關閉nginx服務,等待工作進程處理完所有的請求
Nginx設置靜態文件的緩存過期時間
location ~.*\.(js|css|html|png|jpg)$ {
expires 3d;
}
expires 3d;//表示緩存3天
expires 3h;//表示緩存3小時
expires max;//表示緩存10年
expires -1;//表示永遠過期。
如果設置為-1在js、css等靜態文件在沒有修改的情況下返回的是http 304,如果修改返回http 200
對於靜態資源會自動添加ETag,可以通過添加etag off指令禁止生成ETag。如果是靜態文件,那麼Last-Modified值為文件的最後修改時間。
在開發調試web的時候,經常會碰到因瀏覽器緩存(cache)而經常要去清空緩存或者強制刷新來測試的煩惱,提供下apache不緩存配置和nginx不緩存配置的設置。在常用的緩存設置裡面有兩種方式,都是使用add_header來設置:分別為Cache-Control和Pragma。
location ~ .*\.(css|js|swf|php|htm|html )$ {
add_header Cache-Control no-store;
add_header Pragma no-cache;
}
nginx gzip壓縮
使用 gzip 壓縮可以降低網站帶寬消耗,同時提升訪問速度。
主要在nginx服務端將頁面進行壓縮,然後在瀏覽器端進行解壓和解析,
目前大多數流行的瀏覽器都遲滯gzip格式的壓縮,所以不用擔心。
默認情況下,Nginx的gzip壓縮是關閉的,同時,Nginx默認只對text/html進行壓縮
gzip on;
ersio #開啟gzip壓縮輸出
gzip_http_vn 1.0 ;#默認1.1
#其中的gzip_http_version的設置,它的默認值是1.1,就是說對HTTP/1.1協議的請求才會進行gzip壓縮
#如果我們使用了proxy_pass進行反向代理,那麼nginx和後端的upstream server之間是用HTTP/1.0協議通信的。
gzip_vary on ;
#和http頭有關系,加個vary頭,給代理伺服器用的,有的瀏覽器支持壓縮,有的不支持,
#所以避免浪費不支持的也壓縮,所以根據客戶端的HTTP頭來判斷,是否需要壓縮
gzip_comp_level 6;
#設置gzip壓縮等級,等級越底壓縮速度越快文件壓縮比越小,反之速度越慢文件壓縮比越大 1-9
gzip_proxied any;
#Ngnix作為反向代理的時候啟用
#expample:gzip_proxied no-cache;
# off – 關閉所有的代理結果數據壓縮
# expired – 啟用壓縮,如果header中包含」Expires」頭信息
# no-cache – 啟用壓縮,如果header中包含」Cache-Control:no-cache」頭信息
# no-store – 啟用壓縮,如果header中包含」Cache-Control:no-store」頭信息
# private – 啟用壓縮,如果header中包含」Cache-Control:private」頭信息
# no_last_modified – 啟用壓縮,如果header中包含」Last_Modified」頭信息
# no_etag – 啟用壓縮,如果header中包含「ETag」頭信息
# auth – 啟用壓縮,如果header中包含「Authorization」頭信息
# any – 無條件壓縮所有結果數據
gzip_types text/html ;#壓縮的文件類型
#設置需要壓縮的MIME類型,非設置值不進行壓縮
#param:text/html|application/x-javascript|text/css|application/xml
gzip_buffers 16 8k; #設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間
#設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間
# param1:int 增加的倍數
# param2:int(k) 後面單位是k
# example: gzip_buffers 4 8k;
# Disable gzip for certain browsers.
gzip_disable 「MSIE [1-6].(?!.*SV1)」; #ie6不支持gzip,需要禁用掉ie6
E. WebCache web的緩存機制
1.webcache的簡單介紹
web緩存,是一種 緩存技術 ,用於臨時存儲(緩存)的網頁文件,如HTML頁面和圖像等靜態資源,減少帶寬以及後端伺服器的壓力,通常一個WebCache也是一個 反向代理軟體 ,既可以通過緩存響應用戶的請求,當本地沒有緩存時,可以代理用戶請求至後端主機。
WebCache分為正向和反向之分,一般正向WebCache不常用,這次主要以反向WebCache為主。
2.webcache的由來
1)由於程序具有局部性,而局部性分為: 時間局部性和空間局部性
A.時間局部性是指:在單位時間內,大部分用戶訪問的數據只是熱點數據(熱點數據指經常被訪問的數據)
B.空間局部性是指:某新聞網站突然出來一個重大新聞,此新聞會被被反復訪問。
3.webcache的變化性
WebCache的新鮮度監測機制 :數據都是可變的,所以緩存中的內容要做新鮮度檢測.
4.緩存相關的HTTP首部:
HTTP協議提供了多個首部用以實現 頁面緩存及緩存失效 的相關功能,這其中最常用的有:
1)Expires:HTTP/1.0,用於指定某web對象的過期日期/時間,通常為GMT格式;一般不應該將此設定過長的時間,一年的長度對大多場景來說足矣;其常用於為 純靜態內容 如JavaScripts樣式表或圖片指定緩存周期;
(2)Cache-Control:為了解決HTTP/1.0中對於新鮮度控制的策略而生,通過相對時間來控制緩存使用期限;
(3)Etag:響應首部,用於在 響應報文中為某web資源定義版本標識符 ;
(4)Last-Mofified:響應首部,用於回應客戶端關於Last-Modified-Since或If-None-Match首部的請求,以通知客戶端其請求的web對象最近的修改時間;
(5)If-Modified-Since:條件式請求首部,基於 請求內容的時間戳作驗正 ,如果後端伺服器數據的時間戳未發生改變則繼續使用,反之亦然.
(6)If-None-Match:條件式請求首部; 通過Etag來跟後端伺服器進行匹配 ,如果數據的Etag未發生改變,既不匹配,則響應新數據,否則繼續使用當前數據.
(7)Vary:響應首部,原始伺服器根據請求來源的不同響應的可能會有所不同的首部,最常用的是 Vary: Accept-Encoding,用於通知緩存機制其內容看起來可能不同於用戶請求時 Accept-Encoding-header首部標識的編碼格式;
(8)Age:緩存伺服器可以發送的一個額外的響應首部,用於指定響應的有效期限;瀏覽器通常根據此 首部決定內容的緩存時長;如果響應報文首部還使用了max-age指令,那麼緩存的有效時長為 「max-age減去Age」的結果;
F. ☆前端優化:瀏覽器緩存技術介紹
在前端開發中,性能一直都是被大家所重視的一點,然而判斷一個網站的性能最直觀的就是看網頁打開的速度。 其中提高網頁反應速度的一個方式就是使用緩存 。緩存技術一直一來在WEB技術體系中扮演非常重要角色,是快速且有效地提升性能的手段。
一個優秀的緩存策略可以縮短網頁請求資源的距離,減少延遲,並且由於緩存文件可以重復利用,還可以減少帶寬,降低網路負荷。
所以,緩存技術是無數WEB開發從業人員在工作過程中不可避免的一大問題。 在產品開發的時候我們總是想辦法避免緩存產生,而在產品發布之時又在想策略管理緩存提升網頁的訪問速度 。了解瀏覽器的緩存命中原理,是開發WEB應用的基礎,本文著眼於此,學習瀏覽器緩存的相關知識,總結緩存避免和緩存管理的方法,結合具體的場景說明緩存的相關問題。希望能對有需要的人有所幫助。
在實際WEB開發過程中,緩存技術會涉及到不同層、不同端,比如:用戶層、系統層、代理層、前端、後端、服務端等, 每一層的緩存目標都是一致的,就是盡快返回請求數據、減少延遲 ,但每層使用的技術實現是各有不同,面對不同層、不同端的優劣,選用不同的技術來提升系統響應效率。所以,我們首先看下各層的緩存都有哪些技術,都緩存哪些數據,從整體上,對WEB的緩存技術進行了解,如下圖所示:
本篇文章重點講的就是上面紅色框部分緩存內容。
當瀏覽器請求一個網站的時候,會載入各種各樣的資源,比如:HTML文檔、圖片、CSS和JS等文件。對於一些不經常變的內容,瀏覽器會將他們保存在本地的文件中,下次訪問相同網站的時候,直接載入這些資源,加速訪問。
那麼如何知曉瀏覽器是讀取了緩存還是直接請求伺服器?如下圖網站來做個示例:
第一次打開該網站後,如果再次刷新頁面。會發現瀏覽器載入的眾多資源中,有一部分size有具體數值,然而還有一部分請求,比如圖片、css和js等文件並沒有顯示文件大小,而是顯示了 from dis cache 或者 from memory cache 字樣。這就說明了,該資源直接從本地硬碟或者瀏覽器內存讀取,而並沒有請求伺服器。
瀏覽器啟用緩存至少有兩點顯而易見的好處: (1)減少頁面載入時間;(2)減少伺服器負載;
瀏覽器是否使用緩存、緩存多久,是由伺服器控制的 。准確來說,當瀏覽器請求一個網頁(或者其他資源)時, 伺服器發回的響應的「響應頭」部分的某些欄位指明了有關緩存的關鍵信息 。下面看下,HTTP報文中與緩存相關的首部欄位:
根據上面四種類型的首部欄位不同使用策略, 瀏覽器中緩存可分為強緩存和協商緩存 :
當瀏覽器對某個資源的請求命中了強緩存時, 返回的HTTP狀態為200 ,在chrome的開發者工具的network裡面 size會顯示為from cache ,比如:京東的首頁里就有很多靜態資源配置了強緩存,用chrome打開幾次,再用f12查看network,可以看到有不少請求就是從緩存中載入的:
Expires是HTTP 1.0提出的一個表示資源過期時間的header,它描述的是一個絕對時間,由伺服器返回,用GMT格式的字元串表示 ,如:Expires:Thu, 31 Dec 2037 23:55:55 GMT,包含了Expires頭標簽的文件,就說明瀏覽器對於該文件緩存具有非常大的控制權。
例如,一個文件的Expires值是2020年的1月1日,那麼就代表,在2020年1月1日之前,瀏覽器都可以直接使用該文件的本地緩存文件,而不必去伺服器再次請求該文件,哪怕伺服器文件發生了變化。
所以, Expires是優化中最理想的情況,因為它根本不會產生請求 ,所以後端也就無需考慮查詢快慢。它的緩存原理,如下:
Expires是較老的強緩存管理header, 由於它是伺服器返回的一個絕對時間 ,在伺服器時間與客戶端時間相差較大時,緩存管理容易出現問題, 比如:隨意修改下客戶端時間,就能影響緩存命中的結果 。所以在HTTP 1.1的時候,提出了一個新的header, 就是Cache-Control,這是一個相對時間,在配置緩存的時候,以秒為單位,用數值表示 ,如:Cache-Control:max-age=315360000,它的緩存原理是:
Cache-Control描述的是一個相對時間 ,在進行緩存命中的時候, 都是利用客戶端時間進行判斷 ,所以相比較Expires,Cache-Control的緩存管理更有效,安全一些。
這兩個header可以只啟用一個,也可以同時啟用, 當response header中,Expires和Cache-Control同時存在時,Cache-Control優先順序高於Expires :
此外,還可以為 Cache-Control 指定 public 或 private 標記。 如果使用 private,則表示該資源僅僅屬於發出請求的最終用戶,這將禁止中間伺服器(如代理伺服器)緩存此類資源 。對於包含用戶個人信息的文件(如一個包含用戶名的 HTML 文檔),可以設置 private,一方面由於這些緩存對其他用戶來說沒有任何意義,另一方面用戶可能不希望相關文件儲存在不受信任的伺服器上。需要指出的是,private 並不會使得緩存更加安全,它同樣會傳給中間伺服器(如果網站對於傳輸的安全性要求很高,應該使用傳輸層安全措施)。 對於 public,則允許所有伺服器緩存該資源 。通常情況下,對於所有人都可以訪問的資源(例如網站的 logo、圖片、腳本等), Cache-Control 默認設為 public 是合理的 。
當瀏覽器對某個資源的請求沒有命中強緩存, 就會發一個請求到伺服器,驗證協商緩存是否命中,如果協商緩存命中,請求響應返回的http狀態為304並且會顯示一個Not Modified的字元串 ,比如你打開京東的首頁,按f12打開開發者工具,再按f5刷新頁面,查看network,可以看到有不少請求就是命中了協商緩存的:
查看單個請求的Response Header, 也能看到304的狀態碼和Not Modified的字元串,只要看到這個就可說明這個資源是命中了協商緩存,然後從客戶端緩存中載入的 ,而不是伺服器最新的資源:
【Last-Modified,If-Modified-Since】的控制緩存的原理,如下 :
【Last-Modified,If-Modified-Since】都是根據伺服器時間返回的header,一般來說, 在沒有調整伺服器時間和篡改客戶端緩存的情況下,這兩個header配合起來管理協商緩存是非常可靠的,但是有時候也會伺服器上資源其實有變化,但是最後修改時間卻沒有變化的情況 ,而這種問題又很不容易被定位出來,而當這種情況出現的時候,就會影響協商緩存的可靠性。 所以就有了另外一對header來管理協商緩存,這對header就是【ETag、If-None-Match】 。它們的緩存管理的方式是:
Etag和Last-Modified非常相似,都是用來判斷一個參數,從而決定是否啟用緩存。 但是ETag相對於Last-Modified也有其優勢,可以更加准確的判斷文件內容是否被修改 ,從而在實際操作中實用程度也更高。
協商緩存跟強緩存不一樣,強緩存不發請求到伺服器, 所以有時候資源更新了瀏覽器還不知道,但是協商緩存會發請求到伺服器 ,所以資源是否更新,伺服器肯定知道。大部分web伺服器都默認開啟協商緩存,而且是同時啟用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】,比如apache:
如果沒有協商緩存,每個到伺服器的請求,就都得返回資源內容,這樣伺服器的性能會極差。
【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】一般都是同時啟用,這是為了處理Last-Modified不可靠的情況。有一種場景需要注意:
比如,京東頁面的資源請求,返回的repsonse header就只有Last-Modified,沒有ETag:
協商緩存需要配合強緩存使用,上面這個截圖中,除了Last-Modified這個header,還有強緩存的相關header, 因為如果不啟用強緩存的話,協商緩存根本沒有意義 。
如果資源已經被瀏覽器緩存下來,在緩存失效之前,再次請求時,默認會先檢查是否命中強緩存,如果強緩存命中則直接讀取緩存,如果強緩存沒有命中則發請求到伺服器檢查是否命中協商緩存,如果協商緩存命中,則告訴瀏覽器還是可以從緩存讀取,否則才從伺服器返回最新的資源。其瀏覽器判斷緩存的詳細流程圖,如下: