[]()php
Ryan Albrecht
caisijie 翻譯於2015/12/21android
任何網站都會考慮性能,不論是當地的理髮店或者有巨大知識庫的維基百科。這是一個沒法被忽略的需求。所以緩存變得尤爲重要 —— 一種讓網站變快的極佳途徑,經過保存部分數據,使得下次訪問時不用再次計算或者下載。web
咱們團隊最近在討論Facebook.com沒有被緩存的的部分網頁,問題就來了:Facebook每兩天發佈一次代碼,緩存的效率有多高?咱們是否發佈代碼太頻繁致使瀏覽器的緩存沒有充分利用?爲了找到答案,咱們在Yahoo's Performance Research blog 發現一篇研究關於瀏覽器緩存對網頁性能的影響的文章。數據庫
咱們從中驚訝的發現一個悲觀的結論:有20%的頁面訪問沒有通過緩存。可是這份研究至今已超過8年,那時候瀏覽器還沒法顯示如頂部截圖那樣的瀑布式流量圖,那時候IE7和jQuery才發佈了幾個月。我想忘記這份研究吧,jQuery 1.0 —— 老掉牙了。爲了獲得更精確的結果,咱們決定從新測試看看事情是否有所改觀。瀏覽器
在原來的研究中,Yahoo構造的一種帶特殊頭的圖片。這些頭會告訴瀏覽器若是一樣的圖片被請求兩次,不會進行正常的請求,而是根據圖片是否變更這個條件發送GET請求。這種GET請求會把最後修改時間的頭傳給服務器,若是請求時間和圖片最後修改時間間隔過小,則返回304沒有修改而是否是200成功。Yahoo最後查看服務器日誌進行分析。緩存
與之相似,咱們構建了一個PHP終端來提供圖片以及向數據庫記錄請求。圖片附帶特殊的頭來控制瀏覽器的緩存和中間件的緩存,並且咱們會在請求同時記錄全部頭的信息。而響應頭以下:服務器
Cache-Control: no-cache, private, max-age=0 ETag: abcde Expires: Thu, 15 Apr 2014 20:00:00 GMT Pragma: private Last-Modified: $now // RFC1123 format
在IE7和IE8下,爲了繞過一些已知問題,須要特殊修改:post
Cache-Control: private, max-age=0 Pragma: no-cache
當瀏覽器請求圖片時,會沒有附帶或者附帶一到兩個額外頭部:性能
沒有額外頭部,由於瀏覽器並不認識這個圖片。咱們返回Status: 200 Success
以及 image data ,而後瀏覽器會緩存這些內容。並生成Last-Modified
時間和 ETag
值會已備下次使用。測試
if-none-match
和 if-modified-since
頭的一個或兩個,它說明瀏覽器以前獲取過圖片。服務器會返回Status: 304 Not Modified
而且不包含圖片數據。咱們還把Last-Modified
頭設置爲$header['if-modified-since']
而不是$now
,這樣瀏覽器每次就能得到相同的響應內容。
最後的問題就是何時和在哪裏發送圖片請求。咱們決定在Facebook搜索條旁邊包含一個img
標籤,這樣Facebook每次重載的時候就會渲染。在一個整個頁面的重載中,內存資源會被卸載,而後瀏覽器根據緩存頭從新請求CSS,JavaScript和咱們的圖片。因此這是測量緩存是否工做的最佳位置。
在準備好終端去記錄請求日誌和讓img
標籤去發送請求以後,咱們立刻開始...
通過幾周的數據收集和填滿緩存,對比最後超過7天的數據。初次結果一樣出乎意料:25.5%的請求沒有命中緩存。咱們把數據按接口分類,桌面和移動設備,可是結果類似:桌面版24.8%以及移動版的26.9%請求沒有命中緩存。這不是指望的結果,因此咱們繼續深刻調試。
把桌面數據按瀏覽器劃分後變得一目瞭然。
上圖顯示了桌面瀏覽器一週內的緩存命中率。使用Chrome和Opera顯然從瀏覽器緩存受益更多。你可能注意到Fireforx並無出如今表中,這是有緣由的。Firefox v31和早期版本用當前方法測試的緩存命中率爲80%,過v32版本及以上卻大大的降低。v32 版本說明解釋了緩存後臺會 記錄並重用最近的響應頭。若是重用響應,咱們的終端就無法收到請求並記錄日誌。這樣測試會錯誤的認爲Firefox表現糟糕。但實際上仍在命中本地緩存;只是沒法統計信息。考慮到這點,咱們把Firefox排除在測試結果以外。
讓咱們看看移動端的狀況
不一樣產品的緩存命中在68%和84%之間浮動,和以前的線差很少。移動端的變更性更多,由於許多不一樣 year class 的設備在訪問移動網頁,並且每個瀏覽器版本都有一個可能的範圍。這些數字廣泛比桌面版的低可是排序基本一致。
咱們還能夠看看不一樣用戶命中空緩存的比例
平均44.6%的用戶獲取了空緩存。這佐證了Yahoo在2007年關於每一個用戶命中率的結果。
尚未完呢。在Facebook,咱們但願小步快走的天天兩次地發佈包含當天完成的全部優秀功能。這就引出一個問題:瀏覽器緩存生命週期是多少?咱們能夠經過把請求頭if-modified-since
的值減去當前時間值,這樣就能夠獲得這個用戶命中緩存的存活時間。
因此咱們發掘數據。仍然是最近一週的數據,咱們生成描述緩存持續命中(請求返回304)時間分佈的柱狀圖。換一種說法,每次從新獲取圖片的間隔有多長。
橫軸 duration 單位是小時,豎線 p50_(百分之50), _mean_(平均)和 _p75(百分之75)分別表示對應請求比例的緩存時間。好比,_p50 表示50%的請求在命中最多47小時以前生成的緩存,相似的 p75 代表25%的請求的緩存存在的時間至少有260個小時。在移動端作一樣的分析顯示有50%的請求的緩存不會超過12個小時。
總的來看緩存命中率相比2007年有所提升。若是忽略Firefox v32及以上版本(沒法測試),這樣緩存命中率由2007年的80%左右提升到如今的84.1%。另外一方面,緩存保持活躍的時間並非很長。根據咱們的研究,在桌面版,有42%機率任何請求的緩存的存在時間不超過47小時。這是一個新的維度,並且在某些網站影響突出。
很容易解釋爲何緩存存在時間一般很短。看看因特網如何傳輸和網頁大小size從2007年至今的變化。在2007年,家庭有線帶寬是2.5Mbps,Yahoo主頁168.1KB。現在,我有8Mbps的LTE移動下載帶寬,Yahoo主頁是768KB。如今網頁平均大小是1MB,對瀏覽器優化形成了更大的壓力。
所以利用好瀏覽器緩存仍然重要,若是用好帶來的收益也會比8年前更大。咱們的最佳實踐是使用外部樣式和腳本,包含Cache-Control和Etag頭,傳輸層數據壓縮,使用URL使緩存資源失效,把平凡更新的資源和穩定資源分開。全部這些技術都能在任何網站協同工做,而不僅僅是Facebook。咱們一開始擔憂本身的發佈流程會給緩存性能帶來負面影響,但結果並非這樣。實際上,咱們使用這份數據專一於改進讓全部人訪問www.facebook.com都能經過緩存。真是有意思的一次緩存挖掘之旅。