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=$version$”>的版本化方式,來強制瀏覽器更新快取。
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那個檔案摘要不準啊……..”
“您好,因為天氣原因,去往####的飛機延誤,請您耐心等候……..”
“…….”