網絡流量瘦身建議
浏覽器端用戶所感受到的響應時間受很多因素影響,最主要的來的三個方面:
服務器端的內容生成時間,受服務器端硬件計算能力和服務器的應用程序性能影響
網絡上傳輸數據的時間,受網絡帶寬和所傳輸數據的大小影響
客戶端渲染時間,受客戶端浏覽器性能和客戶端程序性能影響
服務器端和客戶端的性能我們在本系列文章的其他部分中有討論。本部分著重討論如何減少網絡傳輸時間 。用戶與服務器的交互不可避免要在網絡上傳輸數據。尤其是近年來 WEB2.0 等技術的采用,越來越多的交互 和渲染工作轉移到浏覽器端進行,顯示一個頁面需要傳輸的數據也越來越多。而這些數據傳輸的快慢,要傳輸 數據的大小會在很大程度上影響用戶看到的頁面顯示的速度,也就是我們所關心的客戶端的響應時間。如前所 述,這個時間受網絡帶寬和所傳輸數據大小的影響。在既定網絡帶寬的條件下,通過對網絡上待傳輸數據進行 "瘦身",可以有效提升響應速度。
網絡流量不光包含服務器端與客戶端浏覽器之間的網絡 數據傳輸量,如果服務器端是一個基於網絡的多節點環境,各個節點之間的數據也需要在網絡上傳輸,這也需 要花時間。圖 1 所示 ( 此簡化圖中忽略了防火牆,代理服務器,緩存服務器等其他因素 ), 在這個簡化的 應用服務模型中,網絡傳輸既存在於客戶端浏覽器和 Web 服務器之間,也存在於 Web 服務器和應用服務器之 間,以及應用服務器和數據庫服務器之間。如果模型更加復雜,則在代理服務器,緩存服務器等和客戶端以及 主服務器之間也存在網絡流量。因此,減少各個節點之間的數據傳輸次數和數據傳輸量,能夠在很大程度上提 高系統的響應時間和吞吐率,減少性能瓶頸出現的幾率。
要減少網絡流量,一般會在幾方面進行處理 :
只傳輸必要的數據。
如果要在客戶端顯示一個頁面,只傳輸當前頁面顯示所需要的數據就足夠了。一些 為滿足將來可能的操作所需要的數據,可以在頁面顯示之後再做延後傳輸,或者未來操作真正發生的時候再做 傳輸。
對要傳輸的數據進行壓縮。
對於不得不傳輸的內容,可以進行壓縮整理後再做傳輸。對於浏覽器端的客 戶來說,格式整齊可讀性強的代碼對他們沒有意義。但是在不影響頁面效果的情況下,去掉這些 HTML, JSP, javascript, css 等文件裡格式和注釋信息卻對減小文件的大小非常有效。壓縮可以在部署的時候直接往服務 器上放置壓縮整理過的文件,也可以在編譯或者傳輸的時候做壓縮整理相關的設置。
在可能的情況下盡量將數據緩存在接近客戶的節點上。
前面我們了解到,網絡傳輸存在於各層節點之間 。每一層的傳輸都需要花費時間。因此,如果浏覽器端的請求直接從最靠近的節點上拿取數據,不但能節省網 絡傳輸時間,也能節省各個節點上計算和數據存取的時間。因此應當充分發揮從浏覽器到數據庫服務器間各個 層次的緩存能力,並且盡可能將緩存放在靠近用戶的層次上。
圖 1. 網絡傳輸存在於多個環節
本文將給出一些減少網絡數據流量的建議,重點介紹一些減少客戶端浏覽器和服務器之間的網絡傳輸的建 議。讀者可以酌情應用在自己的 WebSphere Commerce 系統中。(文中給出的配置方式基於 WebSphere Commerce V7 Feature Pack 4。)
1. 減少 JSP 的大小
對於 JSP 頁面,有兩方面的冗余可以去除。第一類是編譯時引入的冗余信息,第二類是 JSP 代碼中帶有 的格式,空白和注釋信息等不必要字符。
針對第一類冗余信息,可以使用 useCDataTrim 屬性去除。 建議針對 WebSphere Commerce 7.0 以上使用。該屬性可用於減少 WebSphere Commerce 7.0 以上的的 JSP 頁面編譯時使用 <c:import> 和 <c:param> 標簽所引入的大量空白字符。方法如下:
更 改該路徑下的文件 $WAS_ROOT/profiles/<profile>/config/cells/<cell>/applications/WC_<profile> .ear/deployments/WC_<profile>/Stores.war/WEB-INF/ibm-web-ext.xml, 添加 useCDataTrim 屬性:
…… <jsp-attribute name="keepgenerated" value="true"/> <jsp-attribute name="trackDependencies" value="true"/> <jsp-attribute name="reloadEnabled" value="true"/> <jsp-attribute name="reloadInterval" value="10"/> <jsp-attribute name="useCDataTrim" value="true"/> <reload-interval value="0"/> ……
需要注意的是,為了避免影響片段緩存,還需要保證 WebSphere Application Server 的版本 在 Version 7.0 Fix Pack 7 以上,並且在 Web 容器自定義屬性中設置參數 com.ibm.ws.jsp.getWriterOnEmptyBuffer 為 true。另外,為使更改生效,更改配置文件 ibm-web-ext.xml 之後需要刪除已經編譯過的 JSP 頁面(例如在 $WAS_ROOT/profiles/<profile>/temp 目錄 下的已編譯頁面)以及緩存。為確認該設置生效,可以檢查新編譯後 $WAS_ROOT/profiles/<profile>/temp/WC_<profile>_node/server1/WC_<profile> 下的 JSP 頁面的 .java 文件看是否該屬性已經變為 true:
useCDataTrim = [true]
對於 第二類,也就是 JSP 代碼中帶有的格式信息,空白和注釋信息,可以采用或者自己定制一些文本處理工具, 將文件名以 jsp 或者 jspf 結尾的 JSP 源碼文件處理一遍,刪除其中的空白行,行首位的空白字符以及注釋 信息。放置在目標文件夾中。完成之後將壓縮後的目標文件夾中的 jsp,jspf 文件拷貝到 server 上。同樣 需要注意刪除已經編譯過的 JSP 頁面以及緩存使之生效。
2. 減小 javascript/css 大小
WebSphere Commerce 頁面不可避免會使用大量的外部 javascript 和 css 文件。使這類頁面的文件 體積減少 , 同樣能夠有效降低頁面下載需要的時間。一個與上文中減小 JSP 體積類似的辦法是去除 javascript/css 中的注釋和不必要的空格回車字符。現有的 JS 壓縮工具有很多,比如 YUI Compressor, JSMin, Dojo Compressor, MS Ajax Minifier 等。這裡列出使用 YUI compressor 的方法作為示例:
使用 YUI Compressor 2.4.6 以上版本支持批處理壓縮多個文件。這對於壓縮 Commerce 目錄下的大量 css 和 js 文件很方便。命令如下:(注意:在執行下列命令之前先將要更改的目錄做好備份。)
以 WebSphere Commerce 的示例商店 MadisonsStorefrontAssetStore 為例 ,
$ java -jar yuicompressor_x.x.x.jar -o '.css$:.css'
<WebSphereApp>\Stores.war\MadisonsStorefrontAssetStore\css\*.css
實驗結果是壓縮後最主要的 common1_1.css 的大小減少了約 21%,而整個 css 目錄的大小也減少了 21% 。
同樣的命令可以使用在 javascript 目錄上(同樣請做好目錄備份)。如需對多個目錄以及子目錄進行操作可以編寫腳本調用 YUI Compressor。
需要強調一點,因為 YUI Compressor 去掉了源文件中的注釋,換行以及多余的空格,在壓縮文件大 小的同時也大大降低了可讀性。因此最好能在開發環境和功能測試環境部署未做壓縮的文件以便調試。
一個有用的經驗是:在 WCBD 生成部署包的過程中,會有幾次源文件復制的過程。選擇前面提到的去 空白 / 壓縮程序,封裝成 Ant 任務,在某次源文件復制中調用。這樣就可以在部署過程中實現源代碼的整理 和壓縮,同時不影響開發人員仍舊能看到和使用格式良好的源文件。
3. 將 Web 服務器設置為壓縮傳 輸
將 Web 服務器設置為壓縮傳輸可以有效減小要傳輸到終端客戶的數據的大小,從而節省帶寬以及縮短頁面 數據下載時間。這種方法對於大多數基於文本的頁面非常有效。(WebSphere Commerce 的大多數商店頁面都可 以采用這種方式來進行壓縮傳輸。但是因為 WebSphere Commerce 目前版本的 CMC - Catalog Management Center 是基於 flash 的,因此用此方法壓縮對減小 CMC 的大小沒有效果。)
如下的例 子是更改了 IBM Http Server 的配置文件 httpd.conf(默認該配置文件位於 CommerceServer70/instances/<profile>/httpconf 下)
首先 enable mod_deflate 模塊(去掉該行前面的注釋符):
LoadModule deflate_module modules/mod_deflate.so
然後 增加對於 mod_deflate 的設置如下:
<IfModule mod_deflate.c> DeflateCompressionLevel 9 <Location /> # Insert filter SetOutputFilter DEFLATE # Mozilla 4.x has some problems... BrowserMatch ^Mozilla/4 gzip-only-text/html # Mozilla 4.06-4.08 have some more problems BrowserMatch ^Mozilla/4\.0[678] no-gzip SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary (注:不壓縮圖片) </Location> </IfModule>
示例中的 DeflateCompressionLevel 為頁面壓縮值,最高為 9,最低為 1。對於測試出壓縮後有問題的浏 覽器類型可以使用 BrowserMatch 進行屏蔽(例如圖中對於 Mozilla firefox 4.0 進行了屏蔽)。一般優先 壓縮文本類型的數據,比如 html,js,css 等。不建議對圖片進行壓縮傳輸,因為相對文本壓縮,gzip 壓縮 對圖片不是很有效。如果要對圖片進行壓縮,建議服務器上存放的就是壓縮好的圖片文件,而不是在傳輸的時 候才進行壓縮。
下面兩個圖通過 Firebug 測量顯示了在基本的 WebSphere Commerce 示例商店 MadisonsStorefrontAssetStore 的頁面裡使用壓縮傳輸的效果。圖 2 是使用壓縮傳輸之前的結果,而圖 3 是使用了壓縮傳輸後的結果。可以看到對於文本類的文件,使用壓縮傳輸可以非常有效的減少網絡傳輸的頁面 大小(madisonsesite.html 文件可壓縮至原先大小的 9%),從而減小頁面響應時間,提高高峰訪問時間段的 吞吐率以及避免出現網絡性能瓶頸。
圖 2. 未進行壓縮傳輸的數據大小
圖 3. 使用了壓縮傳輸後的數據大小
從上表的壓縮結果來看 Sample Store 的頁面內容壓縮比非常大(HTML 頁面壓縮後尺寸減小高達 91%)。
4. 縮小圖片尺寸
建議使用 PNG 格式的圖片並對其進行優化。與傳統的 GIF/JPG 格式 的圖片相比,PNG 能在不影響圖片效果的前提下、減少更多的圖片體積,從而減少在網絡上傳輸時占用的帶寬 和時間。
在 Linux 系統下運行 convert 命令,可以將 GIF/JPG 圖片轉為 PNG 格式:
convert image.gif image.png
也可以用以下 shell 命令將整個目錄下的 jpg 圖片批量轉為 PNG 格 式:
$ for i in *.jpg; do convert $i `basename $i .jpg`.png; done
需要注意的是,對於 一些本身已經很小的圖標文件,沒有必要轉化成 PNG 文件(轉化後可能會比原來的體積更大)。
對於 轉化過的 PNG 文件,可以通過一些其他的工具(比如開源工具 Pngcrush)將其作進一步的壓縮處理。 Pngcrush 需要先安裝,而後執行如下命令即可對已有的 PNG 文件做進一步壓縮。
pngcrush src.png dest.png
如果一定要使用 JPG 格式,可以使用 jpegtran。這個工具可以對 JPG 圖片做無損壓縮,同 時它還可以用於優化和清除圖片中的注釋以及其它不必要信息 :
jpegtran -copy none -optimize - perfect – outfile dest.jpg src.jpg
對示例商店 MadisonsStorefrontAssetStore 的廣告圖片的實 驗證明使用 jpegtran 可將 JPG 廣告圖片壓縮至原來的 45% 左右。
5. 浏覽器端緩存
浏覽器 端可以緩存一些靜態頁面(包括圖片)。是否對頁面進行浏覽器緩存,采取什麼方式緩存,以及緩存的淘汰更 新機制一般都通過 http 請求的文件頭來設置。增大靜態頁面過期時間能在一定程度上減少頁面的重復請求從 而減少浏覽器到網絡服務器的數據流量。根據協議,可以在 http 響應頭裡設置 Expires 或者 Cache- Contorl 來設置浏覽器對靜態資源的緩存時間,以減少請求次數。網絡中的緩存服務器也可以根據這些設置緩 存傳輸的靜態資源。如下例子所示:
Cache-Control max-age=3600
Expires Mon, 21 Nov 2011 11:16:40 GMT
Expires 指定一個過期時間。在這個時間之前浏覽器都不會向 服務器發送這個請求,取而代之的是使用浏覽器緩存下來的這個請求的響應內容。Expires 指定的過期時間是 服務器設置的,如果服務器和浏覽器的時間不一致,就不能達到預期的緩存效果,可以使用在 Cache-Control 裡添加 max-age 的方式解決這個問題。Max-age 的值表示這個緩存在多少秒之後過期。比如圖中所示的 max -age 為 3600 秒意味著該 cache 內容會在 1 小時之後過期。需要注意的是 cache-control 的優先級要高於 Expires。所以如果 Expires 和 Cache-Control 的 max-age 參數都設置了的話,會以 Cache-Control 的 max-age 為有效過期時間。
Expires 可以通過在 IBM Http Server 服務器的配置文件 httpd.conf 裡 做默認設置,例如:
LoadModule expires_module modules/mod_expires.so
ExpiresActive On
ExpiresDefault "access plus 1 hours"
生效之後可以通過 Firebug 查看響應 頭信息裡是不是體現出改動,例如下圖中可以看到 Expires 的時間比頁面加載的時間晚 1 小時,說明上述設 置生效。
圖 4. 浏覽器端緩存設置生效
6. 減少 Web 服務器和應用服務器 之間的數據傳輸
減少 Web 服務器和應用服務器之間的數據傳輸不外乎兩種方式:一是將從應用服務器發送到 Web 服務器 的響應內容進行壓縮,去除不必要的信息;二是將一些靜態內容(例如 js,css,圖片,靜態廣告頁,圖片等 )直接存放在 Web 服務器上,從而不需要應用服務器再向 Web 服務器發送這些數據。
應用 服務器壓縮傳輸
前文我們提到過將 Web 服務器發送至客戶端的響應數據設置為 Gzip 壓縮 傳輸的方法。這種方法使用比較普遍。除此之外,用戶也可以通過應用程序自行實現從應用服務器到 Web 服 務器的響應數據壓縮傳輸。實現時注意,程序需要檢查 Http 請求的頭文件以確認浏覽器是否支持 gzip 壓縮 。如果支持 ("accept-encoding"不為空且值含有 gzip)。通過封裝 HttpServletResponseWrapper 和 GZIPOutputStream 類實現對響應的壓縮過濾,從而將壓縮後的響應數據發送給 Web 服務器。
發布時將靜態資源存放到 Web 服務器
WCBD 構建的發布包中的 staticweb 目錄用於存放靜態資源。在發布時,該目錄下的文件會通過 ftp 的方式上傳到 Web 服務器。實現這一步需要 在 WCBD 發布的過程中的某一步選擇 Deploy static web server。選擇這一步驟需要提供設置靜態資源發布 到 Web 服務器的 ant 腳本。WebSphere Commerce 提供了實現這一操作的一系列示例 ant 腳本。如果示例腳 本不能滿足用戶定制的要求,用戶可以定制這些 ant 腳本。
7. 正確使用多級緩存
大量使用緩存除了能減少應用服務器 / 數據庫服務器上的計算量之外,也在很大程度上減少了外部網絡和 分布式環境裡多節點之間的網絡數據傳輸。WebSphere Commerce 建議使用多級緩存的策略,包括:
使用浏覽器端緩存,減少浏覽器和 CDN(內容分發網絡)/Web 服務器間的網絡流量
增加在 CDN/ 邊緣服務器 / 代理服務器的緩存 , 減少這些緩存服務器和 Web 服務器間的網絡流量
將靜態資源盡量存放在 Web 服務器 , 減少 Web 服務器和應用服務器間的網絡流量
使用動態緩存(DynaCache), 包括命令緩存,JSP 緩存 / 片段緩存,數據緩存等,減少應用服務器節點 和數據節點之間的網絡流量。
關於如何正確使用緩存本系列有專門的文章介紹。本文在這裡不再重復敘述。
結束語
本文以提升 WebSphere Commerce 的性能為目標,從代碼壓縮整理,圖片壓縮,緩存等方面給出了一些對 網絡傳輸的數據進行"瘦身"的建議,並提供了在 IBM WebSphere Commerce 的示例商店上進行配置 的例子。讀者可以結合自身的實際,選擇合適的建議加以應用。