Web靜態資源加速
在網際網路應用中WEB頁面的開啟速度,在使用者體驗中佔用極其重要的地位,根據HubSpot所做研究的顯示:如果Yahoo將頁面載入時間減少0.4秒,流量可能會增加9%;頁面慢1秒可能會使亞馬遜每年損失16億美元的銷售額;Bing搜尋的2秒延遲將導致每位訪客的收入損失4.3%,點選量減少3.75%,查詢量下降1.8%。根據上面的資料可以看出,Web頁面的載入時間對網站具有重要的意義。
Web頁面一般包括兩種資源:靜態資源與動態資源。靜態資源主要包括靜態html、圖片、js、css、影片等資源,這些資源基本不會頻繁發生變化,對所有使用者也基本是一致的。動態資源主要為針對每個使用者動態顯示的資料資訊,例如:使用者資訊、登入情況、使用者資料、賬戶餘額、賬戶明細等。動態資源的處理時間主要依賴後臺應用、資料庫的處理效能,可透過提高伺服器效能、最佳化業務處理邏輯來解決,一般需要針對具體的問題來具體分析。本文將主要討論靜態資源的加速技術。
在一段時間內開啟一個網站瀏覽其中的多個頁面,其中會有大量相同的靜態資源請求,由於靜態資源變化頻率較低,可以快取之前已經下載的資源,以備後續的訪問請求。
我們開啟瀏覽器訪問一個頁面,在開發者模式下可以看到如下資訊:
開啟這個頁面一共傳送了303個請求,傳輸了21.6M的資料,總的耗時為11.48秒,整體來看這是一個很慢的頁面(由於用了非同步請求,所以在使用者體驗上還沒有那麼糟糕)。
再次使用F5重新整理頁面,可以看到如下資訊:
這次是300個請求,但是傳輸的資料量只有369K,整體耗時為6.5秒,載入僅有2.5秒,這次在體驗上就非常好,需要頁面顯示的內容很快就顯示出來了,這些就是資源快取的效果。在開發者模式的Network項下,可以看到大量耗時為0ms,size為(memory cache)的請求,標識這些請求,並沒有真正的傳送到伺服器,而是直接在瀏覽器的記憶體快取中讀取,因此他的響應時間是0ms,非常的快!
另外還存在一些size為(disk cache)的請求,這些請求也沒有真正傳送到伺服器,而是在瀏覽器在磁碟的快取中讀取的,由於磁碟的速度比不上記憶體,因此他會有個幾十到幾百的一個處理時間,對於什麼情況下將請求快取到記憶體,什麼情況下將請求快取到硬碟,則是由瀏覽器自己的內部來決定的。在一般情況下,較小的資源會快取到記憶體,較大的資源會快取到磁碟。
還存在一些返回碼為304大小為幾十到一百個位元組的請求。這些請求的資源在本地具有快取,但是快取內容已過期,瀏覽器不確認是否需要更新,因此向伺服器發起請求。伺服器在確認資源沒有過期後將返回不帶報文體的為返回碼304的報文。這種情況下會減少檔案資源的傳輸,降低頻寬的利用,但是由於仍然需要向伺服器發起一次請求,導致處理時間在幾十毫秒到幾秒不等。
那瀏覽器是如何確定哪些資源是可以快取,快取後的資源什麼時候過期,在什麼情況需要更新本地快取資源呢?這些都是透過HTTP 協議報文頭來決定的。快取的方式可以分為兩種型別:本地快取、協商快取。本地快取是直接利用本地快取的資源,不會再向伺服器再次傳送請求。協商快取是根據本地瀏覽器最後一次下載資源的時間、標籤等資訊,向伺服器傳送下載請求,如果伺服器認為本地資源已經是最新的了,則僅僅返回http響應頭,響應程式碼是304,瀏覽器將直接使用本地資源,否則伺服器將按正常的響應返回最新的資源,響應程式碼是200。這兩種快取不併不是互斥的,而是相輔相成的,瀏覽器會優先使用本地快取,如果本地快取已過期將透過協商快取確認快取內容的有效性並更新快取。
可快取的資源一般是靜態資源,但是瀏覽器並不是依據資源型別來判斷是否可以進行快取的,瀏覽器是根據響應碼來判斷是否可快取,只有成功的響應才會被快取,成功的響應碼包括:200(OK)、203( Non-Authoritative Information)、206(Partial Content)、300(Multiple Choices)、301(Moved Permanently)、410(Unauthorized),另外可快取一般是GET請求,POST請求一般不會做快取。
對於資源的是否可以快取、快取的方式、時間,是透過HTTP報文頭來決定的。涉及的HTTP 報文頭屬性包括:Expires、Pragma、Cache-Contrl、Last-Modified/If-Modified-Since、ETag/If-None-Match。
Expires:指定一個絕對時間,在這個時間之後快取中的資源將會過期。
例如:
Expires: Tue, 04 May 2022 22:00:00 GMT
標識資原始檔將會在2022年4月5日星期二 22點過期,過期之前瀏覽器將直接使用記憶體或硬碟中的快取,過期後瀏覽器將再次發起請求獲取新的資源。
Pragma:是一個通用定義,目前只存在一個標準的定義 no-cache,使用方式如下:Pramgma:no-cache
用在請求頭中,表示強制要求快取伺服器將請求提交到源伺服器,這個一般用在代理伺服器上,當我們使用Ctrl+F5重新整理瀏覽器時,在請求頭上會自動帶上這個屬性;
用在響應頭中,要求瀏覽器對快取的資訊在使用時需要伺服器評估快取的有效性,也就是需要將檔案的屬性資訊(檔案修改時間、ETag)傳送到伺服器,如果檔案資源有更新則正常返回,否則返回304告知瀏覽器快取是有效的。因此這裡的no-cahce並不是不快取,而是在使用前需要驗證。如果打算禁止瀏覽器快取,則需要使用HTTP 1.1協議中新增的Cache-Control。
- Pragma和Expires是HTTP 1.0中的標準,在HTTP 1.1中新增了Cache-Control,其功能要更加豐富,常用到的功能定義包括:Public:響應可以被任何物件快取,即使是通常不可以快取的內容;
- Private:響應只允許被單個使用者快取,不能作為共享快取(通常指的是代理伺服器);
- no-cache:同Pramgma: no-cache;
- no-store:這個是我們通常理解的瀏覽器不要快取資料,這時任何請求和響應都不會被快取,新的請求都不會在快取中讀取,需要重新向伺服器發起請求;
- max-age:指定資源在快取中的最大時間週期(單位為秒),超過這個時間週期快取將失效。
Cache-Control: public, max-age=864000標識這個資源可以被任意快取,快取週期為10天;
Cache-Control: no-store標識這個資源不能被瀏覽器快取,因為對他的訪問每次都可能發生變化。
Cache-Control: privete, no-cache, max-age=0標識這個資源可以被快取,但是會立即過期,下次訪問時需要向伺服器發起查詢確認。
透過Cache-Control根據資源的變化情況,可以靈活定義瀏覽器哪些資料可以緩衝、快取的時長。但是被快取的資源一般都是較少發生變化的,大多數情況下過來快取期後,伺服器上的資源也不會發生變化,這個時候也不需要在伺服器重新下載全部資源。這個時候就用到了協商快取。根據HTTP 1.0協議要求,對響應頭裡面需要包含:Last-Modified,標識當前資原始檔的最後修改時間,使用格式為:Last-Modified: Tue, 04 May 2022 22:00:00 GMT
瀏覽器在快取資源時,同時會儲存這個時間,當本地快取過期後再次發起請求,需要在請求頭中包含If-Modified-Since,格式為:Last-Modified-Since: Tue, 04 May 2022 22:00:00 GMT
服務端在接收到這個請求後,將會用這個時間同本地檔案修改時間進行比較,如果本地檔案有更新,將正常返回完成的報文;如果本地的檔案的更新時間沒有發生變化,則返回響應碼為304的響應頭,告訴瀏覽器伺服器檔案未發生變化,節省整個資原始檔的下載時間和流量。
在使用Last-Modified/If-Modified-Since時,需要注意的幾個問題是:
1)時間是精確到秒級的,如果在一秒只能發生多次變化,這種方式是無法識別的,因此不適合變化頻次較高的資源,需要保障變化的間隔時間大於1秒;
2)在負載均衡的多伺服器上釋出時,需要保證各個伺服器上的檔案修改時間是一致的,這種情況一般需要透過tar包釋放的方式釋出;如果直接向各個伺服器直接copy檔案,極有可能各個伺服器的時間不一致,導致資原始檔的更新判斷錯誤,從而出現重複下載的情況。
HTTP 1.1 協議中新增的ETag/If-None-Match則是透過另外一個方式來確定伺服器端的檔案是否發生變化。Etag(Entigy Tag)是根據檔案的屬性生成的一個ID,這些屬性可以包括:inode、修改時間、檔案大小、等檔案屬性資訊,不同的WEB伺服器可以實現自己的ID生成策略,透過這個Etag來代替單一的檔案修改時間來標識檔案是否發生變化。這樣可以解決Last-Modified無法解決的一些問題:
1)有些檔案可能會週期性的被髮布,但是他的內部不一定發了變化,僅僅是由於全量釋出更新了修改時間,這個時候我們不希望客戶認為檔案發生了更新而重新下載;
2)某些檔案修改比較頻繁,修改時間間隔小於1秒,這種修改Last-Modified/If-Modified-Since無法識別。
同時ETag對於叢集部署的服務也存在同Last-Modified一樣的問題,相同的檔案在不同的伺服器上可能生成的Etag是不同的,因為除了檔案的大小外修改時間、Inode可能在不同的伺服器上都不一樣,這時可以自定義ETag的產生方式,保證同一檔案在不同伺服器上ETag的一致。
瀏覽器和伺服器之間可以透過快取技術加速靜態資源的訪問,但是由於當前隨著客戶端介面的豐富和多樣化,需要下載、處理的靜態資源會原來多,存在同時需要下載大量資原始檔的情況,這時也會導致客戶端資源載入緩慢和使用者體驗的下降。
透過上圖可以看到,在下載js檔案時每個檔案的用時達到1~2秒(這個是在內網環境,因此下載速度慢絕對不是網路環境導致的).
檢視在1~2秒的詳細用時,可以看到整體用時1.76秒,Stalled時間為1.67秒,真正下載的時間0.09秒,絕大部分時間都消耗在Stalled上面,根據Chrome的說明出現Stalled狀態可能是由於以下原因:
- 有更高階別的請求;
- 對同一個請求源伺服器已經開啟了6個連結;
- 瀏覽器正在分批磁碟快取。
也就是說瀏覽器為了避免對後臺伺服器帶來特別大的衝擊,最多同時只能開啟6個TCP連結,在這6個連結裡面,所有的資原始檔只能順序下載,其他多餘的資源下載請求只能等待排隊。
因此解決辦法只有減少下載請求數量的次數,具體的方法就是對需要下載資原始檔進行合併。Js、css檔案的合併方式可以為將同型別、同功能、同穩定性的資源合併到一個檔案。對於存在大量小圖片資源的需求,可以將大量的小圖片合併為一個大圖片一次性下載、快取,在使用時透過程式只擷取需要的部分,需要注意的是這種最佳化雖然可以加快資源下載速度,但是可能會增加程式設計的複雜度和瀏覽器的CPU消耗,這兩方面的優略需要根據實際情況進行取捨。
前面介紹的瀏覽器快取技術,主要是透過瀏覽器快取已經訪問過的檔案資源,對下次的訪問起到加速的作用。但是在瀏覽器第一次訪問網站時還是需要下載大量的資源,如果伺服器位於廣州而使用者位於新疆,那整個資源的下載過程還是比較慢的,因為僅僅一次網路傳輸的時間將達到數十毫秒,一次網頁訪問會包括成百上千次的網路傳輸,僅網路傳輸時間就會達到秒級。
這時候就需要用到CDN技術,一種分散式的網路資源快取技術,它既能加速網站靜態資源的下載,又能極大節省網際網路頻寬。CDN的全稱是Content Delivery Network,即內容分發網路,其主要功能是將一個站點上的各種靜態資源,分發到分佈在全國各地的節點上,使使用者可以就近訪問所需資源,從而縮短使用者下載靜態資源的延時,提高使用者訪問網站的響應速度以及網站的可用性。
CDN會在全國乃至全球部署快取伺服器,並提供多種網路運營商接入方式。當客戶端根據域名發起請求時,DNS伺服器會根據客戶端發起請求的IP地址解析出理論上距離最近、訪問速度最快的CDN網路中的快取伺服器IP地址。
CDN快取伺服器快取的資源內容的更新策略主要包括主動更新和被動更新。主動更新就是在源伺服器發生內容更新後,主動通知CDN伺服器進行資源更新,CDN將掃描源站伺服器下指定目錄的所有資源,更新本地的快取伺服器。被動更新就是在客戶端在訪問CDN伺服器時,如果CDN快取伺服器發現在本地快取中不存在,則會向源站伺服器發起回源請求,CDN快取伺服器在獲取最新資源後再保留到本地快取伺服器。
上面介紹的WEB伺服器靜態資源加速技術,主要從技術層透過快取的方式加速靜態資源的下載,但是對越來越豐富多樣的頁面展示來說,需要下載的資源也越來越多,快取技術也不能完全達到滿意的效果,這時就需要結合延遲載入技術。頁面採用分批、逐步渲染的過程,先將一部分內容顯示出來,後臺同時非同步下載其他非必要資源,使得瀏覽器先給使用者展示出部分資訊,而不至於無聊的等待,從而能給使用者帶來更好的使用體驗。另外,還有許多其他的使用者體驗最佳化方法,需要相互結合使用來提高系統的可用性、易用性。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901823/viewspace-2902850/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- web伺服器靜態資源下載Web伺服器
- QTcpServer實現web靜態資源服務QTTCPServerWeb
- Web靜態資源快取及優化Web快取優化
- Nginx服務系列——靜態資源web服務NginxWeb
- Hummingbird - WordPress快取、靜態資源合併、加速外掛快取
- 靜態資源管理
- 前端web:瀏覽器靜態資源快取策略前端Web瀏覽器快取
- 加速部落格體驗:靜態資源最佳化技巧大揭秘!
- 靜態資源公共庫
- webpack 靜態資源管理Web
- WPF:靜態、動態資源以及資源詞典
- WordPress引用靜態資源方法
- 008.Nginx靜態資源Nginx
- Node讀取靜態資源
- SpringBoot處理靜態資源Spring Boot
- SpringBoot靜態資源訪問Spring Boot
- 靜態資源伺服器伺服器
- springboot+themeleaf+bootstrap訪問靜態資源/無法訪問靜態資源/圖片Spring Boot
- 【Nginx】Nginx部署前端靜態資源Nginx前端
- 如何在nginx配置靜態資源Nginx
- Spring Boot 靜態資源配置 A卷Spring Boot
- WPF筆記4——靜態資源(StaticResource)筆記
- Golang 非主流 打包靜態資源方案Golang
- asp .net core 靜態檔案資源
- Nginx靜態資源伺服器配置Nginx伺服器
- Springboot中如何訪問靜態資源Spring Boot
- golang1.16內嵌靜態資源指南Golang
- 如何快速搭建靜態資源伺服器伺服器
- SpringBoot-靜態資源載入-原始碼Spring Boot原始碼
- SpringMVC下關於靜態資源訪問SpringMVC
- springboot新增靜態資源無法訪問Spring Boot
- 手寫Node靜態資源伺服器伺服器
- 模組化開發靜態資源對映
- service worker 對靜態資源進行快取快取
- SpringBoot - 搭建靜態資源儲存伺服器Spring Boot伺服器
- 靜態資源跨域解決辦法--nginx跨域Nginx
- nginx代理出現靜態資源讀取不到Nginx
- nginx 代理圖片、css、js等靜態資源NginxCSSJS