在前端性能優化中應用HTTP緩存的三部曲

文/王岩

Spike先生是Best Experience公司的IT運營部門主管,他的團隊成功地利用Http Cache優化了前端工程。

Spike將通過三個Scenario來展示他的團隊是如何做到這一點的:

  • 通過配置Http Cache Expire來消減訪問壓力,提高用戶體驗
  • 通過版本化來強制失效本地的過期緩存
  • 通過內容摘要命名文件來更精確的控制緩存以及實現非覆蓋式的發布

第一個故事:我不想要那麼多伺服器和帶寬

Best Experience面臨的資源訪問壓力和用戶體驗方面的問題

隨著Best Experience提供的前端應用越來越強大,Spike的壓力也越來越大:

  • IT部門為了應對來自靜態資源的訪問壓力,不斷購置伺服器和帶寬。
  • 糟糕的用戶體驗使得用戶轉投到競爭對手的網站。

工程師們剛剛通過應用Minify、AMD、打包、Gzip等手段優化了前端頁面的體驗, 最終得到如下圖所示的一個資源引用關係:

「還是很多東西要下載啊,該拿什麼來拯救該死的延遲呢?」——Spike看著圖想到。

他突然想起來:在早年間,Yahoo曾發布了關於優化前端體驗的35條建議和指導,其中第三條是:「Add an Expires or a Cache-Control Header」。

Yahoo是這樣描述這條建議的:

Web page designs are getting richer and richer, which means more scripts, stylesheets, images, and Flash in the page. A first-time visitor to your page may have to make several HTTP requests, but by using the Expires header you make those components cacheable. This avoids unnecessary HTTP requests on subsequent page views. Expires headers are most often used with images, but they should be used on all components including scripts, stylesheets, and Flash components.

Browsers (and proxies) use a cache to reduce the number and size of HTTP requests, making web pages load faster.

「這個正是我尋找的銀彈」——Spike得意的笑了。

於是,Spike寫下了第一個Technology Story。

作為IT 部門的老大:

我希望通過應用HTTP緩存技術,重用已經下載過的資源,

用於消減用戶在瀏覽頁面時產生的不必要的Http Request。

以此,來提升用戶在瀏覽頁面時候的體驗,

以及降低對於公司伺服器資源的訪問壓力。

並找來了工程師Tom。

Expire帶來的美好生活

Tom剛剛參與了前一輪的優化工作,雖然成果顯著,但是他並不滿足。

當Tom看到Jim寫下的Story時眼前一亮:「這個方法太贊了!我甚至可以在登錄頁面底部放置對其他頁面資源的引用。提升用戶在整個網站的瀏覽體驗。」——Tom的小宇宙瞬間爆發,很快就完成了新的優化方案。

Best-Experience的用戶在接下來的時間裡瀏覽頁面,會這樣下載資源,以圖片bgimage.png為例:

  • 用戶第一次獲取圖片的時候,Http Request 如圖:

  • 之後用戶再次獲取圖片的時候,則完全可以從瀏覽器的緩存中讀取數據了。

因為採用了Http緩存方案,

  • 用戶的feedback越來越好,訪問量提高了;
  • IT部門也不用那麼多伺服器和帶寬了。

財務總監邀請Spike共進晚餐,並談起了自己在希臘的度假。

「我想我也應該去聖托里尼度個假,犒勞下自己」——Spike美滋滋的想到。

第二個故事:失效緩存是個技術活

這個BUG我們明明修了啊!

一天,QA Tyke發現最近一輪發布的前端應用中沒有包含很多新的feature。Jerry承諾說已經跟著這個月的release上線了,還測試過了。經過一番折騰,Jerry發現瀏覽器一直在使用舊的緩存,而不是最新的版本。Spike找來了Jerry 和Tom,三個人一起手動對引用的資源做了重命名、做了緊急修復。

「真是沒有銀彈啊,我的聖托里尼啊!」——Spike頭疼的想到。

Spike、Jerry、Tom和Tyke坐在了一起,得出了新的結論:

  • 緩存前端工程中的資源時,需要考慮緩存有效期的問題
  • 雖然35條建議和指導中建議「Configure ETags」,但是很難確定靜態資源緩存的有效期
  • 雖然Http緩存可以支持No-Cache或者max-age =0的方式,保證瀏覽器每次都向伺服器驗證緩存有效性,但是這樣會大大增加伺服器的壓力
  • 可以通過在資源引用上增加形如:<…. src=」###.js?v=「>的版本化方式,來強制瀏覽器更新緩存。

Spike寫下了新的Technology Story

作為IT部門的老大:

我希望在前端系統中,對引用的靜態資源進行版本化管理。

使之既可以通過Http緩存來提升用戶體驗,降低伺服器壓力;

也可以方便用戶即時獲得更新後的資源。

「這都10月了,看來是去不成聖托里尼了,總覺得這個方案哪裡有問題」——Spike忐忑不安。

用版本機制來保證瀏覽器更新資源

Jerry和Tom(很難想像他們兩怎麼配合的)終於在前端工程中實現了自動化的資源版本化管理:用戶在最初訪問頁面的時候,會得到這樣一個資源引用:

而當新的版本上線後,用戶會得到這樣一個資源引用:

第三個故事:更精確的緩存管理和平滑升級

(這個案例來自於知乎的大公司里怎樣開發和部署前端代碼? 張雲龍的回答,前一個 story的內容有涉及)

每次更新後的尖峰時刻

11月的Release後,運維人員Nibbles找到Spike,「這次上線以後,伺服器壓力突然劇增,從GA上看到用戶花了很多時間在資源下載上」,Spike找來了Tom、Jerry、Tyke和Nibbles,幾個人坐在一起分析原因:

「這是因為11月的部署完成後,前端應用引用的資源版本升級,所有緩存失效導致的」——Tom 想了想說

「所有的資源引用?我還以為我們能精確到每一個文件的更新呢」——Nibbles驚訝道

「如果單獨標明每一個資源的版本,那麼按照我們的實際情況來看,每次上線後訪問壓力就沒那麼大了」——Tyke

「我之前看WebPack做到了」——Jerry興緻勃勃的談了起來。

「他們採用的是文件摘要的方式,就是用MD5對文件求值,如果兩個文件是相同的,那麼就求得同一個hash值;如果文件是不同的,就求得不同的hash值」——Jerry

「我們可以用這些文件的hash值作為版本號,就像這樣」——Jerry

「能不能通過文件名做版本管理,我希望知道哪些文件是這次部署要移除的,哪些是新增的」——Nibbles

「這有什麼問題么?」——Spike很疑惑

「明年不是要做CDN么?靜態資源和頁面文件會放置到不同的伺服器上,很難做到頁面文件和靜態資源同批次更新,而且CDN的資源生效是有延遲的」——Nibbles

(關於 CDN 和非覆蓋部署式部署,請參考張雲龍的大公司里怎樣開發和部署前端代碼?和前端工程之CDN部署)

「恩,那麼就這樣吧,我回去寫Story。」——Spike 一錘定音。

「還好,我們之前用了WebPack,這就簡單了」——Jerry

Spike寫下了第三個story

作為IT 部門的老大:

我希望能用文件hash來命名靜態資源文件,

使之可以按照文件來控制緩存和部署

「我覺得這回是最後一個Story了」——Spike越來越樂觀。

過渡到非覆蓋式部署——大圓滿?

如何應用WebPack的具體過程不再概述。

圖片來源大公司里怎樣開發和部署前端代碼?

這樣,Nibbles就可以很愉快的通過文件名比對,來分析每次部署變更的內容;而Best Experience未來上線的流程也會變為:

  • 先將新增的靜態資源文件發布到靜態資源伺服器上
  • 驗證新的靜態資源是否正確發布
  • 伺服器暫時離線,替換 html 文件等
  • 刪除無用的靜態資源文件

「終於可以踏踏實實過聖誕節了」——Spike看著日曆。

總結

Spike的總結

年底了,Spike在年終總結中寫到:

以後在實施前端工程中,我們可以通過:

  • 配置永不過期的本地緩存——節約帶寬,提升用戶體驗
  • 採用文件摘要作為緩存依據——更精確的緩存控制
  • 採用CDN——降低用戶請求資源時解析DNS的延遲
  • 利用文件摘要作為文件名——實現非覆蓋式的部署,降低down time

我的總結

我引用前端工程之CDN部署一文中對非覆蓋式、緩存設計、CDN這些解決方案間的前因後果做的總結:

如果考慮到項目開發階段,那麼這將是更為複雜的軟體工程問題。在這個問題域中,還需要囊括文件壓縮、合併、打包、重命名、目錄設置等問題。還好Gulp、Webpack、FIS、AMD、RequireJS這些工具及對應的插件能幫助到我們。WebPack提供了Hash、ChunkHash、ContentHash,與此同時,社區提供了MD5-Hash。

當然這些都是關於工具的話題了,這次我們主要談的是工程。淺談前端集成解決方案里提到了前端領域的8個技術元素與分類,挺有意思的。

再終——沒有銀彈

我們的Spike先生來到了2月的北京旅遊,放個帶色的圖:

我們自強不吸!

在機場,Spike還是接到了Tyke的電話,「老爹啊,WebPack那個文件摘要不準啊……..」

「您好,因為天氣原因,去往####的飛機延誤,請您耐心等候……..」

「…….」

更多精彩洞見,請關注微信公眾號:思特沃克

推薦閱讀:

支持ie8的mvvm框架比較?
前端資訊周報 3.20 - 3.26: 使用Node開發桌面應用入門,以及如何極限壓縮css
產品經理如何在設計產品時避免給開發挖坑?
Web Components 在 GitHub 中的應用

TAG:前端开发 | HTTP | 前端性能优化 |