Facebook讓網站速度提升一倍的BigPipe技術分析

近來[url=http://www.facebook.com/note.php?note_id=389414033919]Facebook高調宣佈將網站性能提高一倍[/url],平均訪問時間從5s降至2.5s,公佈了名爲BigPipe的優化技術的一些概況.性能提升一倍這個結果無疑是極其誘人的,如果各個網站都能應用這種技術拿到這樣的結果,那BigPipe很有可能會成爲匹敵Ajax的技術革新.它究竟是怎樣的?會給你的應用帶來這樣的提升麼?
[b]先來摘要:[/b]
BigPipe原理:再簡單不過了,這就像在餐館吃飯,先選好桌子點好菜(確定用戶佈局和要展現的模塊),單子下到廚房後,多個大廚就可以同時上陣(服務端併發),做好一樣端上來一樣吃一樣(客戶端併發).
BigPipe不具備普適性:網站性能優化再發展下去也不會增加一條類似"儘量減少http數","將CSS放在頁面上部"這樣不加任何說明和限制的優化準則---"使用Bigpipe提高網站速度",也就是說它不可能爲所有應用都帶來提升,或者說bigpipe可能給你的應用帶來提升,但不會像Facebook那麼大.
BigPipe適用的場合:首先,[color=red]網頁第一個請求時間較長[/color]( >500ms? ),在整個網頁展現過程中不再是前端性能優化常說的可以忽略的10-20%.其次頁面上的[color=red]動態內容可以劃分在多個區塊內顯示,且各個區塊之間的關係不大[/color],因爲只是客戶端和服務端併發是不夠的,服務端各個數據中心也要能夠併發才能最好的發揮bigpipe,[color=red]各個區塊的動態數據在服務端也能夠通過url或cookie中的key併發獲得[/color](在facebook,整個key爲userid).除了SNS外,大概搜索結果頁可能可以用上,比如淘寶搜索結果頁的主搜索,類目導航,相關推薦和廣告可以使用BigPipe技術,不過回過頭看第一個限制,如果搜索頁本身很快,那帶來的改進不會如Facebook明顯.
BigPipe的啓示:通過上面的這些限制看到Bigpipe是Facebook量身定做的優化方案,帶來的一點提示是大家可以根據自己的應用爲自己的應用定製優化方案,flush,ajax,靜態資源combo,動態數據combo都是性能優化的手段,如何選擇要看實際情況.
[b]詳細分析:[/b]
之前的一篇文章"[url=http://limu.iteye.com/blog/755628]在Yslow 34 Rules之後 -- 網站性能優化思路和進展[/url]"中提到網站性能優化進入精耕細作階段,儘可能的滿足各種Rules可以保證你能獲得一個性能不錯網站,而更進一步的優化則需要理清優化思路,結合具體應用的實際下功夫.Facebook的BigPipe技術就是這樣發展出來的一種高度契合SNS類應用的優化技術.可以這麼說,網站性能優化再發展下去也不會增加一條類似"儘量減少http數","將CSS放在頁面上部"這樣不加任何說明和限制的優化準則---"使用Bigpipe提高網站速度",也就是說它不可能爲所有應用都帶來提升.我們通過分析這種技術的產生過程,分析SNS類網站頁面的特點,看看和你的應用有沒有匹配的地方,來確定你的應用是否應該選用這種技術.另外也可以學習Facebook性能優化的套路,仔細考慮下自己應用的特點,是不是也能爆出讓人眼前一亮的方案.
下面就開始分析Facebook網頁的特點,網站性能優化的任何資料都經常見到"網頁展現過程百分之八十至九十的時間消耗在了前端"這樣的話,這種斷言主要來自這類最常見的HTTP瀑布圖,如下:
[img]http://dl.iteye.com/upload/attachment/307506/4ebce116-cb0d-3f6b-b403-34ebf601475b.png[/img]
在網頁的生命週期中,到達動態服務器的數據請求往往只是第一個HTML文本請求.相對於這個HTML到達瀏覽器之後再引入的一系列腳本,圖片等等請求以及後續的渲染過程,第一個請求所佔時間相當少.所以一般而言,再怎麼做服務端的優化,對於整個展現過程的加快的幫助微小.但Facebook不同,下面是我的Facebook的個人主頁的首個HTTP請求時間:
[img]http://dl.iteye.com/upload/attachment/307511/ced0681b-7f88-35d2-ad3b-da17f7dc1690.png[/img]
長達3.173s,刨除網絡響應因素,僅接收數據階段,時間也達到了1.65s.Facebook有慢的理由,因爲SNS網站的頁面是高度定製化的,每個區塊的數據都需要大量的計算得來.所以對於Facebook來說,要提升整體頁面響應時間,服務端的時間不得不考慮進去.如何優化?YSlow優化規則中"[url=http://developer.yahoo.com/performance/rules.html#flush]提早Flush[/url]"給了很好的提示."提早Flush"規則建議在</head><body>之間調用flush(),讓這部分內容先輸出給瀏覽器端,這樣瀏覽器端可以在服務端還在生成主體HTML的同時先顯示標題,同時下載<head>中的css和js文件,說到底是服務端和瀏覽器端併發處理頁面展現.但Facebook如果僅做到這樣的"提早flush",對性能的提升不會很明顯.因爲大量的時間消耗在<body>主體內容的生成時段.所以很自然想到需要分塊flush,分塊渲染.而Facebook頁面恰恰可以分塊:
[img]http://dl.iteye.com/upload/attachment/311820/e5e65eba-044e-3c1d-96f4-42cc31625728.jpg[/img]
我們看到Facebook分塊後還有一個特點,就是各個區塊的信息都是動態的,而動態信息都是根據userid查詢得來,各個區塊之間並沒有關聯,"好友動態"和"書籤"完全沒有關係.這樣的特性可以帶來另一個好處,就是服務端併發,Facebook首先取到當前用戶的頁面定製信息,生成佈局,flush出去,然後在服務端就可以根據取到的用戶已定製展現模塊列表,併發請求各個數據中心,這樣在後臺各類應用可以按照統一接口,以區塊劃分,去除了各系統間的耦合.
原理再簡單不過了,這就像在餐館吃飯,先選好桌子點好菜(確定用戶佈局和要展現的模塊),然後單子下到廚房後,多個大廚就可以同時上陣(服務端併發),做好一樣端上來一樣吃一樣(客戶端併發).這樣從瀏覽器端到服務端,在接收數據的這1.5s左右時間之內,真正成了一個流水線.同樣的那些限制條件也很好解釋,吃快餐就完全沒必要一盤菜取一次,每盤菜之間沒什麼關係.好處也顯而易見,每個大廚做自己最擅長的,效率效果都會最優.
[b]Bigpipe作爲完整技術方案的若干技術細節:[/b]
我想任何瞭解flush(),chunked http,Javascript的開發者都能快速開發出Bigpipe的Demo.先輸出佈局HTML,包含若干pagelet(Facebook稱頁面區塊爲pagelet)的容器div.動態數據到達後輸出一段inline script,裏面包含響應的html串和一些配置信息等等,調用onPageletArrived()方法將html片段插入pagelet容器中.上段代碼意思下:

<body>
<div id="layout">
<div id="mod_profile"></div>
<div id="mod_photo"></div>
<div id="mod_friend"></div>
</div>
<?php flush();?><!--首先Flush頁面佈局-->
<script>
//html string for mod_photo
</script>
<?php flush();?><!--Flush #mod_photo的內容-->
<script>
//html string for mod_profile
</script>
<?php flush();?><!--Flush #mod_profile的內容-->
<script>
//html string for mod_friend
</script>
</body>

這裏想討論的是,使用這種方案會引入哪些其他問題,Facebook又是如何解決的.
[b]腳本阻滯:[/b]
我們知道直接在html中引入外部腳本會造成頁面阻滯,即使使用無阻腳本下載的一系列方法引入外部js,但因爲JS單線程,當這些腳本load進來之後運行時也會發生阻滯.因爲Facebook頁面多樣,依賴腳本大小不一,這些阻滯會對頁面的快速展現造成影響.
Facebook做法是在ondomready之前只在頭部輸出一個很小的外部腳本,作爲bigpipe的支撐.其餘所有模塊如果依賴外部腳本(比如某一模塊需要日曆控件支持),都會在domready事件之後加載.這樣做即保證了所有頁面所有模塊都能在domready前快速形成展現,又可以保證無腳本阻滯的快速的domready時間.
[b]最快可交互時間:[/b]
domready再快也至少是在頁面第一個使用bigpipe輸出的chunked的http請求完成之後,對於Facebook來說,這很可能是2秒之後了.那在這2s期間,如果只是頁面展現了而不能交互(點擊日曆無反應),那方案依然不夠完美.
Facebook的做法是,在domready後所依賴腳本已被加載之前,點擊行爲將會生成一個額外的腳本請求,只將這個點擊所依賴的腳步預先load進來.這樣保證了最快的可交互時間.[url=http://ajaxian.com/archives/facebook-javascript-jsconf]Facebook在另一篇文章[/url]中對這個技術進行了詳細的描述.
Bigpipe原理簡單,實現不復雜,但Facebook卻用了1年的時間才形成完備的解決方案.生成方案需要時間,而解決隨之而來的腳本阻滯,保障最快交互時間等等問題也會消耗大量時間.
[b]總結一下:[/b]
Bigpipe在Facebook獲得巨大成功,我想在於對細節的深度挖掘.如果第一個請求時間不用那麼長,那相當於去吃麥當勞還分兩次拿薯條和漢堡.如果服務端不能併發,那肯定達不到如此好的優化效果.如果不排除外聯腳本的下載和運行阻滯帶來的不確定性,也得不到如此高的展現速度.同時如果不對domready前的click按需加載處理,可交互性會大打折扣.當然Facebook可能還有更多我們不知道的類似的技術細節,所有這些細節聯合起來,才能得到這樣漂亮的結果.
系統優化是個浩大的工程,在Yslow Rules這類規則默認遵守之後,要想再獲得突破,那隻能從自身的應用出發做選最合適的方案.同時Bigpipe出現不意味着Ajax過時了落伍了.頁面的動態數據來自多個數據中心,那麼用Bigpipe吧.如果一個頁面上的動態數據可以用一個Ajax請求獲得,那完全沒必要用它.大多數應用第一個http請求的時間依然只用了很短的時間,所以Ajax還是主流.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章