關於大型網站技術演進的思考(二十)--網站靜態化處理—web前端優化—中(12)

  Web前端不少優化原則都是從如何提高網絡通信效率的角度提出的,可是這些原則使用的時候仍是有不少陷阱在裏面,若是咱們不能深刻理解這些優化原則背後所隱藏的技術原理,頗有可能掉進這些陷阱裏,最終沒有達到最佳的預期效果,今天我在這裏分析下瀏覽器和服務端通信的一些細節問題,但願經過分析這些細節問題,能給你們一個啓迪,能更好的理解這些優化原則背後的隱祕,最終能更好的運用這些原則。javascript

  網站的通信技術是構建在http協議上,http協議底層通信手段使用的是tcp/ip協議,可是tcp通信協議在創建鏈接和斷開鏈接這兩個動做上是很是消耗通信性能的,這主要是由於tcp/ip協議在鏈接創建時候的三次握手機制和斷開鏈接時候的四次揮手機制所致,咱們來看看下面的圖形:css

 

  圖中中間被紅色標記的方塊就是tcp/ip協議在創建鏈接時候須要發送三次報文才能確認鏈接是否創建成功,中間四個藍色的方框就是說明tcp/ip協議在斷開鏈接時候要發四次報文才能肯定鏈接最終被斷開,而一個具體的http請求和響應也就發送兩次報文,這也就說明若是瀏覽器每次和服務端的交互都要新建和關閉一個tcp/ip鏈接,那麼瀏覽器和服務器之間就要往返9次報文通信,而真正用來處理用戶請求的報文確只有其中的兩次,換句話說這樣的一個請求大概會有80%左右的性能都不是用來處理業務需求,等因而損失了80%左右的性能,固然這個比率是9次報文交互的數據大小一致狀況下得出的,若是用戶業務請求和響應的數據量比較大,那麼創建鏈接和斷開鏈接的性能損失佔比會下降,不過就算佔比下降了那也是在請求處理自己的時間變的更慢的基礎上的下降,要是瀏覽器和服務器之間的距離特別大,那麼多出來的7次報文交換的效率問題就更加嚴重了,無論怎樣,tcp/ip的三次握手機制和四次揮手機制只要發生都會對網絡請求效率產生重大影響。html

  爲了解決這個報文交互次數過多的問題,http協議自己也發生了改變,那就是http開始採用了長鏈接,使用長鏈接後網站只須要開啓一個長鏈接,在用戶關閉瀏覽器關閉以前瀏覽器裏的網頁都會複用這個長鏈接。不過http協議的1.0版本默認是不啓用長鏈接的,因此在使用http協議1.0版本時候我就得手動的打開長鏈接,這個方法就是在http頭裏設置Connection: Keep-Alive,而http1.1版本里長鏈接是默認打開的,因此不須要咱們手動的設置,並且時下的瀏覽器幾乎都支持http1.1協議,所以大多時候狀況下咱們是沒有必要手動去打開長鏈接的。前端

  雖然http協議採用長鏈接後能夠減小網站通信時候三次握手和四次揮手的次數,可是長鏈接創建起來後須要瀏覽器和服務器長時間維護,這自己會消耗瀏覽器和服務器的性能,特別是服務器端長時間維護長鏈接自己還會損壞服務器處理併發的能力,因此早期瀏覽器會限制http1.1開啓鏈接的數量,例如ie7這個古董瀏覽器,它准許http1.1最多開啓2個長鏈接,而http1.0由於默認使用短鏈接它默承認以開啓4個,下面有張圖能夠說明,以下所示:java

 

  提高瀏覽器加載效率的手段除了提高每一個鏈接的傳輸效率外,其實還有一種方式,這個方式就是使用多個鏈接進行並行加載,這個等於幾我的聯合起來一塊兒完成一個任務,那麼效率確定就比一我的高,而頁面加載時候很符合使用併發加載的場景,例如咱們讓頁面裏的圖片並行加載確定會比一個個加載圖片的效率要高多了。回到瀏覽器支持的鏈接數的問題,因爲早期瀏覽器在http1.0和http1.1鏈接數的差別,某些網站例如維基百科這樣的網站,它的靜態資源特別多,爲了充分發揮併發的優點,它將存放這些靜態資源的服務器採用http1.0協議,這樣就能並行加載更多的靜態資源,由於這個並行加載的整體效率提高相比tcp/ip握手和揮手的損失要高的多,不過如今這個手法已經起不到什麼做用了,由於新版的瀏覽器已經把兩種版本的http協議支持的鏈接數調整一致了,由於長鏈接能夠複用鏈路,所以使用長鏈接的效率會比非長鏈接更好。web

  上面鏈接數也是有一個限制的,這個限制就是必須是在同一個域名下,若是一個頁面某些靜態資源放在不一樣域名下面,那麼這個作法就能夠增長頁面裏的併發數量,例如咱們把一些不是常常變化的靜態資源例如圖片、外部的css文件以及javascript文件單獨放置在一個靜態資源服務器上,靜態資源服務器對外的url地址和頁面自己的url地址不在同一個域名下,那麼頁面自己的併發加載鏈接數就會增長一倍,不過這也就意味着瀏覽器端要維護的長鏈接數會變得更多,雅虎工程師曾經總結過一個頁面裏合理的域名數量,那就是兩個,這個結論的提出已通過去了好多年了,如今的瀏覽器和服務器的性能已經今非昔比了,這個跨域數量應該能夠增長點,不過我我的認爲一個頁面的裏包含的域名數量仍是不要太多,其實若是咱們web前端優化手段使用得當,兩個不一樣域名就足夠用了,多了價值不大,除非你網站狀況是在特殊,例如你看看如今瀏覽器自己支持的鏈接數量已經很高了,大部分都是6,ie9甚至還達到了10,翻個倍就有12和20個鏈接數,咱們在翻個倍就是24和40個,這個數字看起來就很恐怖了,一個計算機支持這麼多併發,假如你在瀏覽器還打開個網站也是這麼幹的,那麼瀏覽器的併發數多的實在太嚇人了,我估計到時計算機自己就跑不動了,因此10多個鏈接數很夠用了,你合理發揮下這些鏈接數網站的性能就能有很大提高,再說了一個網站併發鏈接數太多那自己就說明了你在減小http個數這個手段沒有運用好。ajax

  回到web前端優化的手段,咱們若是把這些手段再仔細分析下就會發現不少手段使用都是在同步請求這個場景下進行了,固然這些手段在合適狀況下也能做用於異步加載場景,可是異步加載場景發生併發加載以前須要一個單線程的異步加載,這個單線程的異步加載就和分佈式系統裏的單點故障有點像了,它頗有多是整個流程的軟肋所在,因此合理使用同步請求還能讓異步操做性能更加優秀作好準備。上面我講到瀏覽器在同一個域名下最多能夠開啓多少個鏈接數,可是從事web前端開發的人都能感受到,咱們作頁面開發時候實際上是無法控制這個鏈接數的,那麼問題來了,這麼多鏈接究竟是在什麼條件下被開啓的呢?這個問題很是有意思的,咱們來看下面的瀑布圖:跨域

 

  從上面的瀑布圖咱們發現,並行下載的是圖片,這個推而廣之要是咱們看見某些網站的網頁作過併發優化處理的設計,咱們就會發現併發的資源都是純靜態的資源,那麼這個併發鏈接數跟咱們頁面的設計存在一個怎樣的關係呢?首先咱們總結一下頁面裏的靜態資源,在頁面裏靜態資源有html,若是html裏面有內聯的css代碼和javascript代碼,那麼這些代碼也會歸屬於html,除了html外還有外部的css文件、外部的javascript文件和頁面裏使用到的圖片,那麼這些要素怎樣會促發頁面的並行加載了,換個說法這些要素又是如何促使瀏覽器同時打開更多鏈接呢?瀏覽器

  首先咱們要明確一個問題,瀏覽器之因此能夠打開更多鏈接數,讓這麼多鏈接並行執行是有個前提的,這個前提就是這些資源是否是被並行加載的,例如像外部css文件,圖片這樣的資源,這些資源下載完畢後立刻就可使用,由於它們下載完畢後沒有邏輯性問題要處理所以下載完畢後就能夠直接拿來使用,所以它們並行加載不會影響到頁面的展現問題,這個狀況若是碰到javascript就有點麻煩了,外部javascript代碼是包含邏輯在裏面,並且有些邏輯頗有可能會影響頁面的展現,因此javascript下載完畢後,瀏覽器就得立刻執行,因此咱們就會看到這樣的瀑布圖,以下圖所示:服務器

 

  上面的空白區就是瀏覽器在執行javascript代碼所要花費的時間。瀏覽器開啓多少個鏈接是瀏覽器自發的行爲,這個自發行爲主要出於提高瀏覽器併發下載效率的角度出發的。因爲如今瀏覽器的鏈接基本都是採起的是http1.1協議,也就是使用的長鏈接,那麼鏈接創建後這個鏈接就會長期維護,若是這個長鏈接是單獨的靜態資源服務器上的長鏈接,這個問題倒沒什麼,若是這個長鏈接放在主域名下面,問題就來了,主域名在頁面初始化加載時候會用來下載html,若是咱們爲提升併發下載效率,讓這個主域名下還放置其餘的靜態資源,那麼可能會致使瀏覽器和主域名的服務器下維護更多的長鏈接,而頁面後續操做基本是使用ajax來操做的,而ajax每每只會複用其中一個長鏈接,那麼其餘多餘的長鏈接等於要空轉了,這個空轉還須要消耗瀏覽器和服務器的系統資源,因此咱們發現主域名下的請求資源類型必定要認真加以控制,能遷移到單獨的靜態資源服務器上的必定要進行遷移,儘可能讓主域名下處理的請求都是包含業務邏輯的請求,這樣就能夠有效提高系統資源的使用率。這個問題進一步思考下去,咱們就會發現若是服務端的業務應用服務器以前放置一個反向代理,反向代理都是使用靜態資源服務器,而靜態資源服務器對併發的承載能力是遠超業務應用服務器,若是主域名下咱們不當心放置了太多靜態資源,要是後臺使用了反向代理,那麼反向代理也能夠減輕這種長鏈接所形成的計算資源損失。

  上面這些場景都是在瀏覽器同步請求下進行了,那麼換到異步請求這個並行加載靜態資源的手段還有效嗎?回答這個問題前,咱們首先要想一想異步加載會致使新的靜態資源被加載嗎?這個固然可能,特別是在前端MVC的場景下,咱們會把模板技術放到瀏覽器端完成,這個時候有些html模板一開始可能會包含在javascript代碼裏,做爲一個變量存儲下來,而這個模板裏頗有可能包含好多新的圖片被使用,當ajax從服務端獲取數據後,解析了這個模板,而後咱們把構造好的模板加入到頁面的DOM結構裏,瀏覽器從新渲染頁面時候看到不少新圖片須要加載,就有可能會開啓多個鏈接進行並行加載來提高資源加載效率,若是碰到經過ajax技術動態加載外部CSS文件,那麼這個並行加載狀況就會更加突出了,由於css文件裏頗有可能包含大量的圖片資源,若是咱們把不變的靜態資源都放置在了單獨的靜態資源服務器,那麼這個並行加載就不會在主域名下打開更多長鏈接,因而可知,將靜態資源使用單獨的域名的靜態資源服務器處理的好處很是之多。

  如今http2.0協議還在起草之中,http2.0若是落地將會給web前端優化技術產生重大影響,http2.0打算在一個頁面裏只使用一個tcp/Ip鏈接,不過http2.0會在這個鏈接上進行鏈路複用,也就是讓一個鏈接上也能作到並行操做,讓鏈接的利用率更高,若是http2.0落地後,web前端裏那些用於減小http鏈接數的手段都會失去市場了,由於協議自己就能處理好併發的問題了,到時像外部css文件,外部javascript文件,css sprite技術說不定就要成爲歷史了。

  看來本主題又寫不完了,下篇接着寫吧,今天是元宵節,這裏我祝你們節日快樂。

相關文章
相關標籤/搜索