緩存設計詳解:低成本的高性能Web應用解決方案
譯文【51CTO精選譯文】過去幾年中,Web應用程序已經從簡單的HTML頁面堆積演變成使用各種各樣的技術構建高可擴展性和交互式的富應用程序。設計和開發這類應用程序變得越來越復雜,此外,決策者正越來越多地尋求構建更豐富的互動功能到這些應用程序中,同時還要保證可維護性和高性能,但高性能意味著高成本。為了構建提供給最終用戶體驗的是一個牢固的應用程序,開發人員需要解決潛在的性能瓶頸。
本文側重于緩存——它是交付高性能Web應用程序急需的——也簡要介紹一下壓縮功能。有一些公司在生產和銷售專門的壓縮和性能產品。本文旨在簡單介紹在尋求專業產品解決性能問題之前開發人員可以在客戶端和服務器端對Web應用程序做的一些性能改進。
性能瓶頸
性能瓶頸主要體現在高延時、擁塞和服務器負載。緩存不能完全解決掉這三個問題,但經過詳細的設計考慮,緩存是可以提高性能的。在服務器端和客戶端都緩存內容,據調查,平均而言,下載HTML只需要總的用戶響應時間的10-20%,剩下的80-90%全部用于下載頁面中的其它組成內容,這些組成內容通常包括圖像,如公司logo,緩存logo可以有效避免到服務器的多次往返。在前日51CTO上發布的加速,加速,再加速:來自Google的網站加速技巧大全中,Google提到的提升網站速度和性能的低成本技巧中就包括緩存這一條。至于架構設計方面,則可參考51CTO的視頻專題:大型網站架構專家談。
簡單地講,緩存是臨時存儲。它將數據復制到不同的計算機或不同于原始數據源的位置,有了正確的配置,訪問緩存數據的速度比訪問原始數據的速度要快得多,使用緩存數據可以減小服務器負載和帶寬消耗,從最終用戶的角度來看就是性能提高了。
圖1顯示了Internet如何工作的快速總攬,以及緩存在哪里發生作用。
圖 1 Internet上的緩存:這個圖顯示了常見的請求和檢索緩存信息的時機
緩存
正如你在圖1中所看到的,在服務器和客戶端上緩存數據既是可能的也是有效的,圖2顯示了這三個緩存位置的不同視圖。
圖 2 緩存配置:此圖顯示了三個典型的緩存位置
1、客戶端瀏覽器緩存:瀏覽器緩存Web對象后,可以對重復的請求直接響應,不用再從Internet請求數據了。
2、服務器端轉發代理緩存:雖然可能有些變化,但這些緩存位置通常是在最終用戶防火墻里面,可以對請求直接響應,不需要從原始來源請求數據。
3、服務器端反向代理緩存:也被稱為網關或代理緩存,這些緩存服務器的操作代表了客戶的來源服務器,術語“內容分發網絡(CDN)”就是這些反向代理緩存的集合。
你可以緩存任何可能不止一次被請求的對象,但總有一個危險就是緩存的對象很可能變得陳舊,也就是說,沒有準確地反應原始數據。不過可以使用兩個參數來控制所有可緩存的對象:freshness和validation。freshness和validation都可以使用HTTP請求和相應組合來進行確定。
◆Freshness確定某個對象是否可以從緩存中獲得,使用expires和cache-control:max-age頭進行控制。
◆Validation確定某個對象是否已經陳舊,使用last-modified和if-modified-since頭進行控制。
設計高度緩存的Web應用程序
企業級Web應用程序既有靜態部分又有動態部分,只要進行了正確的設計和架構,都能夠實現靜態部分從緩存中獲取,動態部分從原始服務器獲取,但第一步是確定要緩存什么,圖3提供了一個指南,可以幫助你確定哪些對象是可緩存,哪些對象是動態的(不可緩存的)。
圖 3 確定緩存能力:此圖提供了某個對象是否應該緩存的指南
應用程序架構在可緩存對象和不可緩存對象之間有一點差異,開發人員應該尋求最大限度的緩存命中率,同時要避免緩存動態對象。下面是一些最佳實踐:
1、使用緩存控制(cache-control:max-age)和有效期(Expires)頭
2、使用最后修改時間(last-modified)頭
3、檢查Web服務器是否支持If-Modified-Since
4、調查為小型站點使用轉向代理的可行性,或為大型企業網站從CDN廠家獲得專業人員的幫助
5、根據網站的可擴展性思考是使用數據中心還是托管
6、自己動手編碼常常需要大量的時間和精力,根據站點的規模,可以考慮采用開源緩存方法,如使用Squid作為代理服務器
7、為文件下載明確使用混合緩存機制
8、確保那些無用戶/輸入依賴的動態事務可以獲得緩存,為不同對象創建緩存映像可以幫助將可緩存對象和不可緩存對象隔離開來
9、小心完全忽略緩存頭的內容管理系統(CMS)
#p#
為緩存使用頭(Header)
本節覆蓋了為緩存目的最有用的頭。
控制緩存
在HTTP 1.1規范中,服務器應該為緩存控制頭發送一個無緩存響應,以指出內容不應該被緩存,客戶端和服務器端都應該遵守這個頭信息,以防止頭中已經聲明了的動態內容,大多數開發語言都支持使用這個頭信息控制響應頭值。
另一方面,你可以為cache-control頭返回一個public服務器端應答來允許緩存(即使沒有cache-control頭也可以指出對象是可以緩存的),cache-control頭的值為private是一個特殊情況,表示瀏覽器可能會在本地緩存對象,但代理服務器不會緩存它。
圖4中的請求——響應工作流顯示了Google如何通過cache-control頭通知代理服務器不要緩存的。
圖 4 停止代理服務器緩存:請求--應答流顯示服務器返回private阻止代理服務器緩存
最后,服務器使用expires應答時包括了一個表示有效期的日期/時間戳,直到有效期滿之前瀏覽器都可以緩存中的對象。如圖5所示。
圖 5 過期內容:Google的Gmail服務器返回一個expires頭,包括緩存頁面的過期日期和時間
這一點你可以驗證,Gmail允許瀏覽器緩存Gmail主頁,直到expires頭中明確指定的時間到了為止。
使用Last-Modified 頭
瀏覽器使用這個頭信息來確定緩存對象生存期的有效性,瀏覽器請求這個對象時,服務器使用一個包含該對象最后修改時間的時間戳的Last-Modified 頭進行響應,當用戶下次請求相同的對象時,如果當前的時間戳超出了對象的使用期限,或者用戶是通過刷新方式請求該頁面的,瀏覽器會向服務器發送一個if_modified_since請求確定對象是否發生了變化,如果對象的確發生了變化,瀏覽器就發送一個完整的GET請求以獲取新的對象并將其再次緩存起來,否則,瀏覽器就從它的緩存中提取對象,并更新對象的last-modified值。圖6顯示了一個工作實例。
圖 6 最后修改時間:last-modified時間戳讓瀏覽器確定是使用本地緩存內容還是重新請求內容
舉一個例子,假設瀏覽器在請求www.yahoo.com時,服務器使用last-modified時間戳進行響應,和使用if-modified-since頭進行響應(參考圖7)時對比一下,看行為有何不同。
圖 7 檢查修改:通過發送if-modified-since頭,服務器將會使用一個表示自時間戳指定時間以來是否發生了變化的值進行響應
在圖7中,瀏覽器使用if-modified-since頭發送一個請求,服務器使用304代碼進行響應,表示瀏覽器可以使用緩存,不用發起一個完整的GET請求。
為了全面理解這些頭信息的效果,最好的辦法是你自己動手實驗一翻,使用各種不同的頭信息組合,并觀察它們的行為,分析頭信息的一個好工具是Wfetch。
自己動手的方法
正如前面給出的建議,自己動手(DIY)的方法并不總是捷徑,專門提供CDN加速的產品和解決方案可以滿足不同類型的需求。但如果你要開發的是一個內部使用的產品,可以提供幫助的可能只有Squid了,Squid被用作許多產品的一個組成部分,許多ISP也在使用它。例如,在Java應用程序中,Squid可以被用作Tomcat服務器的代理,Squid提供的不僅僅是HTTP緩存,但關于它的完整介紹已經超出了本文的范圍,請讀者自行搜索相關文章,可以在Wikimedia看到另一個使用Squid的例子。
HTTP壓縮
緩存僅僅是提高Web應用程序性能的方法之一,壓縮是另一個關鍵方法,HTTP壓縮在內容發送到客戶端之前將其壓縮,在客戶端和服務器端都有壓縮功能,當服務器交付的是壓縮內容時,由瀏覽器進行解壓,這樣可以節約寶貴的帶寬,減少成本和提高響應時間。
瀏覽器使用值為gzip的accept-encoding—typically頭宣稱它們支持壓縮,服務器使用content-encoding頭指定應答數據的編碼,例如,如果使用的是gzip格式進行壓縮,服務器應該使用值為gzip的content-encoding 頭進行響應。
服務器檢查響應的MIME類型,只壓縮那些通過壓縮可以獲得好處的類型,如文本文件、HTML和PDF文件,圖像格式如gif文件不會從壓縮技術獲得什么好處,因為gif本身已經是壓縮格式了,視頻文件以及其它預壓縮的二進制文件也不會從壓縮功能獲得好處。
注意:代理服務器應該和來源服務器支持同類型的壓縮。
總體而言,結合緩存和壓縮功能可以提高Web應用程序的性能,因此還提高了應用程序的可擴展性。
原文:A Guide to Caching and Compression for High Performance Web Applications
作者:Puneet Sangal
【編輯推薦】