自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Google Chrome中的高性能網(wǎng)絡(luò)

開發(fā) 前端
Google Chrome的歷史和指導(dǎo)原則 【譯注】這部分不再詳細(xì)翻譯,只列出核心意思。

Google Chrome的歷史和指導(dǎo)原則 【譯注】這部分不再詳細(xì)翻譯,只列出核心意思。

驅(qū)動Chrome繼續(xù)前進的核心原則包括:

  • 速度: 做最快的(fastest)的瀏覽器。
  • 安全(Security):為用戶提供最為安全的(most secure)的上網(wǎng)環(huán)境。
  • 穩(wěn)定: 提供一個健壯且穩(wěn)定的(resilient and stable)的Web應(yīng)用平臺。
  • 簡單: 以簡練的用戶體驗(simple user experience)封裝精益求精的技術(shù)(sophisticated technology)。

本文關(guān)將注于第一點——速度。

關(guān)于性能的方方面面

一個現(xiàn)代瀏覽器就是一個和操作系統(tǒng)一樣的平臺。在Chrome之前的瀏覽器都是單進程的應(yīng)用,所有頁面共享相同的地址空間和資源。引入多進程架構(gòu)這是Chrome最為著名的改進【譯注:省略一些反復(fù)談?wù)摰募?xì)節(jié)】。

120131107095439

一個進程內(nèi),Web應(yīng)用主要需要執(zhí)行三個任務(wù):獲取資源,頁面 排版及渲染,和運行JavaScript。渲染和腳本都是在運行中交替以單線程的方式運行的,其原因是為了保持DOM的一致性,而JavaScript本 身也是一個單線程的語言。所以優(yōu)化渲染和腳本運行無論對于頁面開發(fā)者還是瀏覽器開發(fā)者都是極為重要的。

Chrome的渲染引擎是WebKit, JavaScript Engine則使用深入優(yōu)論的V8 (“V8″ JavaScript runtime)。但是,如果網(wǎng)絡(luò)不暢,無論優(yōu)化V8的JavaScript執(zhí)行,還是優(yōu)化WebKit的解析和渲染,作用其實很有限。巧婦難為無米之 炊,數(shù)據(jù)沒來就得等著!

相對于用戶體驗,作用最為明顯的就是如何優(yōu)化網(wǎng)絡(luò)資源的加載順 序、優(yōu)先級及每一個資源的延遲時間(latency)。也許你察覺不到,Chrome網(wǎng)絡(luò)模塊每天都在進步,逐步降低每個資源的加載成本:向DNS lookups學(xué)習(xí),記住頁面拓?fù)浣Y(jié)構(gòu)(topology of the web), 預(yù)先連接可能的目標(biāo)網(wǎng)址,等等,還有很多。從外面來看就是一個簡單的資源加載的機制,但在內(nèi)部卻是一個精彩的世界。

關(guān)于Web應(yīng)用

開始正題前,還是先來了解一下現(xiàn)在網(wǎng)頁或者Web應(yīng)用在網(wǎng)絡(luò)上的需求。

HTTP Archive 項目一直在追蹤網(wǎng)頁構(gòu)建。除了頁面內(nèi)容外,它還會分析流行頁面使用的資源數(shù)量,類型,頭信息以及不同目標(biāo)地址的元數(shù)據(jù)(metadata)。下面是2013年1月的統(tǒng)計資料,由300,000目標(biāo)頁面得出的平均數(shù)據(jù):

220131107095457

1280 KB 包含88個資源(Images,JavaScript,CSS …)

連接15個以上的不同主機(distinct hosts)。

這些數(shù)字在過去幾年中一直持續(xù)增長( steadily increasing ),沒有停下的跡象。這說明我們正不斷地建構(gòu)一個更加龐大的、野心勃勃的網(wǎng)絡(luò)應(yīng)用。還要注意,平均來看每個資源不過12KB, 表明絕大多數(shù)的網(wǎng)絡(luò)傳輸都是短促(short and bursty)的。這和TCP針對大數(shù)據(jù)、流式(streaming)下載的方向不一致,正因為如此,而引入了一些并發(fā)癥。下面就用一個例子來抽絲剝繭, 一窺究竟……

一個Resource Request的一生 W3C的Navigation Timing specification定義了一組API,可以觀察到瀏覽器的每一個請求(request)的時序和性能數(shù)據(jù)。下面了解一些細(xì)節(jié):

320131107095509

給定一個網(wǎng)頁資源地址后,瀏覽器就會檢查本地緩存和應(yīng)用緩存。如果之前獲取過并且有相應(yīng)的緩存信息(appropriate cache headers)(如Expires, Cache-Control, etc.), 就會用緩存數(shù)據(jù)填充這個請求,畢竟最快的請求就是沒有請求(the fastest request is a request not made)。否則,我們重新驗證資源,如果已經(jīng)失效(expired),或者根本就沒見過,一個耗費網(wǎng)絡(luò)的請求就無法避免地發(fā)送了。

給定了一個主機名和資源路徑后,Chrome先是檢查現(xiàn)有已建立的連接(existing open connections)是否可以復(fù)用, 即sockets指定了以(scheme、host和port)定義的連接池(pool)。但如果配置了一個代理,或者指定了 proxy auto-config (PAC)腳本,Chrome就會檢查與proxy的連接。PAC腳本基于URL提供不同的代理,或者為此指定了特定 的規(guī)則。與每一個代理間都可以有自己的socket pool。最后,上述情況都不存在,這個請求就會從DNS查詢(DNS lookup)開始了,以便獲得它的IP地址。

幸運的話,這個主機名已經(jīng)被緩存過。否則,必須先發(fā)起一個 DNS Query。這個過程所需的時間和ISP,頁面的知名度,主機名在中間緩存(intermediate caches)的可能性,以及authoritative servers的響應(yīng)時間這些因素有關(guān)。也就是說這里變量很多,不過一般還不致于到幾百毫秒那么夸張。

420131107095522

拿到解析出的IP后,Chrome就會在目標(biāo)地址間打開一個新TCP連接,我們就要執(zhí)行一個3度握手(“three-way handshake”): SYN > SYN-ACK > ACK。這個操作每個新的TCP連接都必須完成,沒有捷徑。根據(jù)遠(yuǎn)近,路由路徑的選擇,這個過程可能要耗時幾百毫秒,甚至幾秒。而到現(xiàn)在,我們連一個有效 的字節(jié)都還沒收到。

當(dāng)TCP握手完成了,如果我們連接的是一個HTTPS地址,還有一個SSL握手過程,同時又要增加最多兩輪的延遲等待。如果SSL會話被緩存了,就只需一次。

最后,Chrome終于要發(fā)送HTTP請求了 (如上面圖示中的requestStart)。 服務(wù)器收到請求后,就會傳送響應(yīng)數(shù)據(jù)(response data)回到客戶端。這里包含最少的往返延遲和服務(wù)的處理時間。然后一個請求就完成了。但是,如果是一個HTTP重定向(redirect)的話?我們 又要從頭開始這個過程。如果你的頁面里有些冗余的重定向,最好三思一下!

你得出所有的延遲時間了嗎? 我們假設(shè)一個典型的寬帶環(huán)境:沒有本地緩存,相對較快的DNS lookup(50ms), TCP握手,SSL協(xié)商,以及一個較快服務(wù)器響應(yīng)時間(100ms)和一次延遲(80ms,在美國國內(nèi)的平均值): 50ms for DNS 80ms for TCP handshake (one RTT)

  • 160ms for SSL handshake (two RTT’s)
  • 40ms (發(fā)送請求到服務(wù)器)
  • 100ms (服務(wù)器處理)
  • 40ms (服務(wù)器回傳響應(yīng)數(shù)據(jù))

一個請求花了470毫秒, 其中80%的時間被網(wǎng)絡(luò)延遲占去了??吹搅税?,我們真得有很多事情要做!事實上,470毫秒已經(jīng)很樂觀了:

如果服務(wù)器沒有達到到初始TCP的擁塞窗口(congestion window),即4-15KB,就會引入更多的往返延遲。 SSL延遲也可能變得更糟。如果需要獲取一個沒有的認(rèn)證(certificate)或者執(zhí)行 online certificate status check (OCSP), 都會讓我們需要一個新的TCP連接,又增加了數(shù)百至上千毫秒的延遲。

#p#

怎樣才算”夠快”?

前面可以看到服務(wù)器響應(yīng)時間僅是總延遲時間的20%,其它都被DNS,握手等操作占用了。過去用戶體驗研究( user experience research )表明用戶對延遲時間的不同反應(yīng):

延遲及用戶反應(yīng) 0 – 100ms 迅速 100 – 300ms 有點慢 300 – 1000ms 機器還在運行 1s+ 想想別的事…… 10s+ 我一會再來看看吧…

上表同樣適用于頁面的性能表現(xiàn): 渲染頁面,至少要在250ms內(nèi)給個回應(yīng)來吸引住用戶。這就是簡單地針對速度。從Google, Amazon, Microsoft,以及其它數(shù)千個站點來看,額外的延遲直接影響頁面表現(xiàn):流暢的頁面會吸引更多的瀏覽、以及更強的用戶吸引力(engagement) 和頁面轉(zhuǎn)換率(conversion rates).

現(xiàn)在我們知道了理想的延遲時間是250ms,而前面的示例告訴我們,DNS Lookup, TCP和SSL握手,以及request的準(zhǔn)備時間花去了370ms, 即便不考慮服務(wù)器處理時間,我們也超出了50%。

對于絕大多數(shù)的用戶和網(wǎng)頁開發(fā)者來說,DNS, TCP,以及SSL延遲都是透明,很少有人會想到它。這也就是為什么Chrome的網(wǎng)絡(luò)模塊那么的復(fù)雜。

我們已經(jīng)識別出了問題,下面讓我們深入一下實現(xiàn)的細(xì)節(jié)…

深入Chrome的網(wǎng)絡(luò)模塊 多進程架構(gòu)

Chrome的多進程架構(gòu)為瀏覽器的網(wǎng)絡(luò)請求處理帶來了重要意義,它目前支持四種不同的執(zhí)行模式( four different execution models ).

默認(rèn)情況下,桌面的Chrome瀏覽器使用process- per-site模式, 將不同的網(wǎng)站頁面隔離起來, 相同網(wǎng)站的頁面組織在一起。舉個簡單的例子: 每個tab獨立一個進程。從網(wǎng)絡(luò)性能的角度上說,并沒什么本質(zhì)上的不同,只是process-per- tabl模式更易于理解。

520131107095531

每一個tab有一個渲染進程(render process),其中包括了用于解析頁面(interpreting)和排版(layout out)的WebKit的排版引擎(layout engine), 即上圖中的HTML Render。還有V8引擎和兩者之間的DOM Bindings,如果你對這部分很好奇,可以看這里( great introduction to the plumbing )。

每一個這樣的渲染進程被運行在一個沙箱環(huán)境中,只會對用戶的電 腦環(huán)境做極有限的訪問–包括網(wǎng)絡(luò)。而使用這些資源,每一個渲染進程必須和瀏覽內(nèi)核進程(browser[kernel] process)溝通,以管理每個渲染進程的安全性和訪問策略(access policies)。

進程間通訊(IPC)和多進程資源加載

渲染進程和內(nèi)核進程之間的通訊是通過IPC完成的。在Linux和 Mac OS上,使用了一個提供異步命名管道通訊方式的socketpair()。每一個渲染進程的消息會被序列化地到一個專用的I/O線程中,然后再由它發(fā)到內(nèi) 核進程。在接收端,內(nèi)核進程提供一個過濾接口(filter interface)用于解析資源相關(guān)的IPC請求( ResourceMessageFilter ), 這部分就是網(wǎng)絡(luò)模塊負(fù)責(zé)的。

620131107095544

這樣做其中一個好處是所有的資源請求都由I/O進程處理,無論是UI產(chǎn)生的活動,或者網(wǎng)絡(luò)事件觸發(fā)的交互。在內(nèi)核進程(browser /kernel process)的I/O線程解析資源請求消息,將轉(zhuǎn)發(fā)到一個ResourceDispatcherHost的單例(singleton)對象中處理。

這個單例接口允許瀏覽器控制每個渲染進程對網(wǎng)絡(luò)的訪問,也能達到有效和一致的資源共享:

Socket pool 和 connection limits: 瀏覽器可以限定每一個profile打開256個sockets, 每個proxy打開32個sockets, 而每一組{scheme, host, port}可以打開6個。注意同時針對一組{host,port}最多允計打開6個HTTP和6個HTTPS連接。 Socket reuse: 在Socket Pool中提供持久可用的TCP connections,以供復(fù)用。這樣可以為新的連接避免額外建立DNS、TCP和SSL(如果需要的話)所花費的時間。

Socket late-binding(延遲綁定): 網(wǎng) 絡(luò)請求總是當(dāng)Scoket準(zhǔn)備好發(fā)送數(shù)據(jù)時才與一個TCP連接關(guān)連起來,所以首先有機會做到對請求有效分級(prioritization),比如,在 socket連接過程中可能會到達到一個更高優(yōu)先級的請求。同時也可以有更好的吞吐率(throughput),比如,在連接打開過程中,去復(fù)用一個剛好 可用的socket, 就可以使用到一個完全可用的TCP連接。其實傳統(tǒng)的TCP pre-connect(預(yù)連接)及其它大量的優(yōu)化方法也是這個效果。

Consistent session state (一致的會話狀態(tài)): 授權(quán)、cookies及緩存數(shù)據(jù)會在所有渲染進程間共享。

Global resource and network optimizations (全局資源和網(wǎng)絡(luò)優(yōu)化): 瀏覽器能夠在所有渲染進程和未處理的請求間做更優(yōu)的決策。比如給當(dāng)前tab對應(yīng)的請求以更好的優(yōu)先級。

Predictive optimizations (預(yù)測優(yōu)化): 通過監(jiān)控網(wǎng)絡(luò)活動,Chrome會建立并持續(xù)改善預(yù)測模型來提升性能。

… 項目還在增加中.

單就一個渲染進程而言, 透過IPC發(fā)送資源請求很容易,只要告訴瀏覽器內(nèi)核進程一個唯一ID, 后面就交給內(nèi)核進程處理了。

跨平臺的資源加載

跨平臺也是Chrome網(wǎng)絡(luò)模塊的一個主要考量,包括Linux, Windows, OS X, Chrome OS, Android, 和iOS。 為此,網(wǎng)絡(luò)模塊盡量實現(xiàn)成了單進程模式(只分出了獨立的cache和proxy進程)的跨平臺函數(shù)庫, 這樣就可以在平臺間共用基礎(chǔ)組件(infrastructure)并分享相同的性能優(yōu)化,更有機會做到同時為所有平臺進行優(yōu)化。

相關(guān)的代碼可以在這里找到the “src/net” subdirectory)。本文不會詳細(xì)展開每個組件,不過了解一下代碼結(jié)構(gòu)可以幫助我們理解它的能力結(jié)構(gòu)。 比如:

net/android 綁定到Android 運行時(runtime) [譯注(Horky):運行時真是一個很爛的術(shù)語,翻和沒翻一樣。] net/base 公共的網(wǎng)絡(luò)工具函數(shù)。比如,主機解析, cookies, 網(wǎng)絡(luò)轉(zhuǎn)換偵測(network change detection),以及SSL認(rèn)證管理 net/cookies 實現(xiàn)了Cookie的存儲、管理及獲取 net/disk_cache 磁盤和內(nèi)存緩存的實現(xiàn) net/dns 實現(xiàn)了一個異步的DNS解析器(DNS resolver) net/http 實現(xiàn)了HTTP協(xié)議 net/proxy 代理(SOCKS 和 HTTP)配置、解析(resolution) 、腳本抓取(script fetching), … net/socket TCP sockets,SSL streams和socket pools的跨平臺實現(xiàn) net/spdy 實現(xiàn)了SPDY協(xié)議 net/url_request URLRequest, URLRequestContext和URLRequestJob的實現(xiàn) net/websockets 實現(xiàn)了WebSockets協(xié)議 上面每一項都值得好好讀讀,代碼組織的很好,你還會發(fā)現(xiàn)大量的單元測試。

#p#

Mobile平臺上的架構(gòu)和性能

移動瀏覽器正在大發(fā)展,Chrome團隊也視優(yōu)化移動端的體驗為最高優(yōu)先級。先要說明的是移動版的Chrome的并不是其桌面版本的直接移植,因為那樣根本不會帶來好的用戶體驗。移動端的先天特性就決定了它是一個資源嚴(yán)重受限的環(huán)境,在運行參數(shù)有一些基本的不同:

桌面用戶使用鼠標(biāo)操作,可以有重疊的窗口,大的屏幕,也不用擔(dān)心電池。網(wǎng)絡(luò)也非常穩(wěn)定,有大量的存儲空間和內(nèi)存。 移動端的用戶則是觸摸和手勢操作,屏幕小,電池電量有限,通過只能用龜速且昂貴的網(wǎng)絡(luò),存儲空間和內(nèi)存也是相當(dāng)受限。

再者,不但沒有典型的樣板移動設(shè)備,反而是有一大批各色硬件的設(shè)備。Chrome要做的,只能是設(shè)法兼容這些設(shè)備。好在Chrome有不同的運行模式(execution models),面對這些問題,游刃有余!

在Android版本上,Chrome同樣運用了桌面版本的多進程架構(gòu)- 一個瀏覽器內(nèi)核進程,以及一個或多個渲染進程。但因為內(nèi)存的限制,移動版的Chrome無法為每一個tabl運行一個特定的渲染進程,而是根據(jù)內(nèi)存情況等 條件決定一個最佳的渲染進程個數(shù),然后就會在多個tab間共享這些渲染進程。

如果內(nèi)存實在不足,或其它原因?qū)е翪hrome無法運行多進程,它就會切到單進程、多線程的模式。比如在iOS設(shè)備上,因為其沙箱機制的限制,Chrome只能運行在這種模式下。

關(guān)于網(wǎng)絡(luò)性能,首先Chrome在Android和iOS使用的是 各其它平臺相同的網(wǎng)絡(luò)模塊。這可以做到跨平臺的網(wǎng)絡(luò)優(yōu)化,這也是Chrome明顯領(lǐng)先的優(yōu)勢之一。所不同的是需要經(jīng)常根據(jù)網(wǎng)絡(luò)情況和設(shè)備能力進行些調(diào)整, 包括推測優(yōu)化(speculative optimization)的優(yōu)先級、socket的超時設(shè)置和管理邏輯、緩存大小等。

比如,為了延長電池壽命,移動端的Chrome會傾向于延遲關(guān)閉空 閑的sockets (lazy closing of idle sockets), 通常是為了減少信號(radio)的使用而在打開新的socket時關(guān)閉舊的。另外因為預(yù)渲染(pre-rendering,稍后會介紹)會使用一定的網(wǎng) 絡(luò)和處理資源,它通常只在WiFi才會使用。

關(guān)于移動瀏覽體驗會獨立一章,也許就在POSA系列的下一期。

Chrome Predictor的預(yù)測功能優(yōu)化

Chrome會隨著使用變得更快。 它這個特性是通過一個單例對象Predictor來實現(xiàn)的。這個對象在瀏覽器內(nèi)核進程(Browser Kernel Process)中實例化,它唯一的職責(zé)就是觀察和學(xué)習(xí)當(dāng)前網(wǎng)絡(luò)活動方式,提前預(yù)估用戶下一步的操作。下面是一個示例:

用戶將鼠標(biāo)停留在一個鏈接上,就預(yù)示著一個用戶的偏好以及下一步的瀏覽行為。這時Chrome就可以提前進行DNS Lookup及TCP握手。用戶的點擊操作平均需要將近200ms,在這個時間就可能處理完DNS和TCP相關(guān)的操作, 也就是省去幾百毫秒的延遲時間。 當(dāng)在地址欄(Omnibox/URL bar) 觸發(fā)高可能性選項時,就同樣會觸發(fā)一個DNS lookup和TCP預(yù)連接(pre-connect),甚至在一個不可見的頁簽中進行預(yù)渲染(pre-render)!

我們每個人都一串天天會訪問的網(wǎng)站, Chrome會研究在這些頁面上的子資源, 并且嘗試進行預(yù)解析(pre-resolve), 甚至可能會進行預(yù)加載(pre-fetch)以優(yōu)化瀏覽體驗。

除了上面三項,還有很多..

Chrome會在你使用過程中學(xué)習(xí)Web的拓?fù)浣Y(jié)構(gòu),而不單單是你的瀏覽模式。理想的話,它將為你省去數(shù)百毫秒的延遲, 更接近于即時頁面加載的狀態(tài). 正是為了這個目標(biāo),Chrome投入了以下的核心優(yōu)化技術(shù):

DNS預(yù)解析(pre-resolve) 提前解析主機地址,以減少DNS延遲 TCP預(yù)連接(pre-connect) 提前連接到目標(biāo)服務(wù)器,以減少TCP握手延遲 資源預(yù)加載(prefetching) 提前加載頁面的核心資源,以加載頁面顯示 頁面預(yù)渲染(prerendering)
提前獲取整個頁面和相關(guān)子資源,這樣可以做到及時顯示

每一個決策都包含著一個或多個的優(yōu)化, 用來克服大量的限制因素. 不過畢竟都只是預(yù)測性的優(yōu)化策略,如果效果不理想,就會引入多余的處理和網(wǎng)絡(luò)傳輸。甚至可能會帶來一些加載時間上的負(fù)體驗。

Chrome如何處理這些問題呢? Predictor會盡量收集各種信息,諸如用戶操作,歷史瀏覽數(shù)據(jù),以及來自渲染引擎(render)和網(wǎng)絡(luò)模塊自身的信息。

和Chrome中負(fù)責(zé)網(wǎng)絡(luò)事務(wù)調(diào)度的ResourceDispatcherHost不同,Predictor對象會針對用戶和網(wǎng)絡(luò)事務(wù)創(chuàng)建一組過濾器(filter):

IPC channel filter用來監(jiān)控來自render進程的事務(wù)。 每個請求上都會加一個ConnectInterceptor 對象,這樣就可以跟蹤網(wǎng)絡(luò)傳輸?shù)哪J揭约懊恳粋€請求的度量數(shù)據(jù)。

渲染進程(render process)會在一系列的事件下發(fā)送消息到瀏覽器進程(browser process), 這些事件被定義在一個枚舉(ResolutionMotivation)中以便于使用 (url_info.h):

enum ResolutionMotivation { MOUSE_OVER_MOTIVATED, // 鼠標(biāo)懸停. OMNIBOX_MOTIVATED, // Omni-box建議進行解析. STARTUP_LIST_MOTIVATED, // 這是在前10個啟動項中的資源. EARLY_LOAD_MOTIVATED, // 有時需要使用prefetched來提前建立連接.

// 下面定義了預(yù)加載評估的方式,會由一個navigation變量指定. // referring_url_也需要同時指定. STATIC_REFERAL_MOTIVATED, // 外部數(shù)據(jù)庫(External Database)建議進行解析。 LEARNED_REFERAL_MOTIVATED, // 前一次瀏覽(prior navigation建議進行解析. SELF_REFERAL_MOTIVATED, // 猜測下一個連接是不是需要進行解析.

// <略> … }; 通過這些給定的事 件,Predictor的目標(biāo)就可以評估它成功的可能性, 然后再適時觸發(fā)操作。每一項事件都有其成功的機率、優(yōu)先級以及時間戳,這些可以在內(nèi)部維護一個用優(yōu)先級管理的隊列,也是優(yōu)化的一個手段。最終,對于這個隊 列中發(fā)出的每一個請求的成功率,都可以被Predictor追蹤到?;谶@些數(shù)據(jù),Predictor就可以進一步優(yōu)化它的決策。

Chrome網(wǎng)絡(luò)架構(gòu)小結(jié)

Chrome使用多進程架構(gòu),將渲染進程同瀏覽器進程隔離開來。 Chrome維護著一個資源分發(fā)器的實例(a single instance of the resource dispatcher), 它運行在瀏覽器內(nèi)核進程,并在各個渲染進程間共享。

網(wǎng)絡(luò)層是跨平臺的,大部分情況下以單進程庫存在。

網(wǎng)絡(luò)層使用非阻塞式(no-blocking)操作來管理所有網(wǎng)絡(luò)任務(wù)。

共享的網(wǎng)絡(luò)層支持有效的資源排序、復(fù)用、并為瀏覽器提供在多進程間進行全局優(yōu)化的能力。

每一個渲染進程通過IPC和資源分發(fā)器(resource dispatcher)通訊。

資源分發(fā)器(Resource dispatcher)通過自定義的IPC Filter解析資源請求。

Predictor在解析資源請求和響應(yīng)網(wǎng)絡(luò)事務(wù)中學(xué)習(xí),并對后續(xù)的網(wǎng)絡(luò)請求進行優(yōu)化。

Predictor會根據(jù)學(xué)習(xí)到的網(wǎng)絡(luò)事務(wù)模式預(yù)測性的進行DNS解析, TCP握手,甚至是資源請求,為用戶實際操作時節(jié)省數(shù)百毫秒的時間。

了解晦澀的內(nèi)部細(xì)節(jié)后,讓我們來看一下用戶可以感受到的優(yōu)化。一切從全新的Chrome開始。

#p#

優(yōu)化冷啟動(Cold-Boot)體驗

第一次啟動瀏覽器,它當(dāng)然不可能了解你的使用習(xí)慣和喜歡的頁面。但事實上,我們大多數(shù)會在瀏覽器的冷啟動后做些類似的事情,比如到電子郵箱查看郵 件,加一些新聞頁面、社交頁面及內(nèi)部 頁面到我的最愛,諸如此類。這些頁面各有不同,但它們?nèi)匀痪哂幸恍┫嗨菩裕訮redictor仍然可以對這個過程提速。

Chrome記下了用戶在全新啟動瀏覽器時最常用的10個域名。當(dāng)瀏覽器啟動時,Chrome會提前對這些域名進行DNS預(yù)解析。你可以在Chrome中使用chrome://dns查看到這個列表。在打開頁面的最上面的表格中會列出啟動時的備選域名列表。 720131107095555

通過Omnibox優(yōu)化與用戶的交互

引入Omnibox是Chrome的一項創(chuàng)新, 并不是簡單地處理目標(biāo)的URL。除了記錄之前訪問過的頁面URL,它還與搜索引擎的整合,并且支持在歷史記錄中進行全文搜索(比如,直接輸入頁面名稱)。

當(dāng)用戶輸入時,Omnibox自動發(fā)起一個行為,要么查找瀏覽記錄中的URL, 要么進行一次搜索。每一次發(fā)起的操作都會被加以評分,以統(tǒng)計它的性能。你可以在Chrome輸入chrome://predictors來觀察這些數(shù)據(jù)。 820131107095605

Chrome維護著一個歷史記錄,內(nèi)容包括用戶輸入的前置文字,采用的行為,以命中的資數(shù)。 在上面的列表,你可以看到,當(dāng)輸入g時,有76%的機會嘗試打開Gmail. 如果再補充一個m (就是gm), 打開Gmail的可能性增加到99.8%。

那么網(wǎng)絡(luò)模塊會做什么呢?上 表中的黃色和綠色對于ResourceDispatcher非常重要。如果有一個一般可能性的頁面(黃色), Chrome就是發(fā)起DNS預(yù)解析。如果有一個高可能性的頁面(綠色),Chrome還會在DNS解析后發(fā)起TCP預(yù)連接。如果這兩項都完成了,用戶仍然 繼續(xù)錄入,Chrome就會在一個隱藏的頁簽進行預(yù)渲染(pre-render)。

相對的,如果輸入的前置文字找不到合適的匹配項目,Chrome會向搜索引擎服務(wù)者發(fā)起DNS預(yù)解析和TCP預(yù)連,以獲取相似的搜索結(jié)果。

平均而言用戶從填寫查詢內(nèi)容到評估給出的建議需要花費數(shù)百毫秒。 此時Chrome可以在后臺進行預(yù)解析,預(yù)連接,甚至進行預(yù)渲染。再當(dāng)用戶準(zhǔn)備按下回車鍵時,大量的網(wǎng)絡(luò)延遲已經(jīng)被提前處理掉了。

優(yōu)化緩存性能

最快的請求就是沒有請求。 無論何時討論性能,都不能不談緩存。相信你已經(jīng)為頁面上所有資源的都提供了Expires, ETag, Last-Modified和Cache-Control這些響應(yīng)頭信息(response headers)。什么? 還沒有?那你還是先處理好再來看吧!

Chrome有兩種不同的內(nèi)部緩存的實現(xiàn):一種備份于本地磁盤(local disk),另一種則存儲于內(nèi)存(in-memory)中。內(nèi)存模式(in-memory)主要應(yīng)用于無痕瀏覽模式(Incognito browsing mode),并在關(guān)閉窗口清除掉。 兩種方式使用了相同的內(nèi)部接口(disk_cache::Backend, 和disk_cache::Entry),大大簡化了系統(tǒng)架構(gòu)。如果你想實現(xiàn)一個自己的緩存算法,可以很容易地實現(xiàn)進去。

在內(nèi)部,磁盤緩存(disk cache)實現(xiàn)了它自己的一組數(shù)據(jù)結(jié)構(gòu), 它們被存儲在一個單獨的緩存目錄里。其中有索引文件(在瀏覽器啟動時加載到內(nèi)存中),數(shù)據(jù)文件(存儲著實際數(shù)據(jù),以及HTTP頭以及其它信息)。比較有趣 的是,16KB以下的文件存儲于共同的數(shù)據(jù)塊文件中(data block-files,即小文件集中存儲于一個大文件中),其它較大的文件才會存儲到自己專屬的文件中。最后,磁盤緩存的淘汰策略是維護一個LRU,通 過比如訪問頻率和資源的使用時間(age)的度量進行管理。

 920131107095617

在Chrome開個頁簽,輸入chrome://net-internals/#httpCache。 如果你要看到實際的HTTP數(shù)據(jù)和緩存的響應(yīng)處理,可以打開chrome://cache, 里面會列出所有緩存中可用的資源。打開每一項,還可以看到詳細(xì)的數(shù)據(jù)頭等信息。

優(yōu)化DNS預(yù)連接

前面已經(jīng)多次提到了DNS預(yù)解析,在深入實現(xiàn)之前,先匯總一下DNS預(yù)解析的場景和理由:

運行在渲染進程中的WebKit文檔解析器(document parser), 會為當(dāng)前頁面上所有的鏈接提供一個主機名(hostname)列表,Chrome可以選擇是否提前解析。 當(dāng)用戶要打開頁面時,渲染進程先會觸發(fā)一個鼠標(biāo)懸停(hover)或按鍵(button down)事件。

Omnibox可能會針對一個高可能性的建議頁面發(fā)起解析請求。

Chrome Predictor會基于過往瀏覽記錄和資源請求數(shù)據(jù)發(fā)起主機解析請求。(下面會詳細(xì)解釋。)

頁面本身會顯式地要求Chrome對某些主機名稱進行預(yù)解析。

上述各項對于Chrome都只是一個線索。 Chrome 并不保證預(yù)解析一定會被執(zhí)行,所有的線索會由Predictor進行評估,以決定后續(xù)的操作。最壞的情況下,可能無法及時解析主機名,用戶就必須等待一個 DNS解析時間,然后是TCP連接時間,最后是資源加載時間。Predictor會記下這個場景,在未來決策時相應(yīng)地加以參考??傊欢ㄊ窃接迷娇?。

之前提過到Chrome可以 記住每個頁面的拓?fù)?topology),并可以基于這個信息進行加速。還記得吧,平均每個頁面帶有88個資源,分別來自于30多個獨立的主機。每打開這 個頁面,Chrome會記下資源中比較常用的主機名,在后續(xù)的瀏覽過程中,Chrome就會發(fā)起針對某些主機或者全部主機的DNS解析,甚至是TCP預(yù)連接!

1020131107095626

#p#

使用chrome://dns 就可以觀察到上面的數(shù)據(jù)(Google+頁面), 其中有6個子資源對應(yīng)的主機名,并記錄了DNS預(yù)解析發(fā)生的次數(shù),TCP預(yù)連接發(fā)生的次數(shù),以及到每個主機的請求次數(shù)。這些數(shù)據(jù)就可以讓Chrome Predictor執(zhí)行相應(yīng)的優(yōu)化決策。

除了內(nèi)部事件通知外,頁面設(shè)計者可以在頁面中嵌入如下的語句請求瀏覽器進行預(yù)解析:

之所以有這個需求,一個典型的例子是重定向(redirects). Chrome本身沒辦法判斷出這種模式,通過這種方式則可以讓瀏覽器提前進行解析。

具體的實現(xiàn)也是因版本而有所差異,總體而言,Chrome中的DNS處理有兩個主要的實現(xiàn):1.基于歷史數(shù)據(jù)(historically), 通過調(diào)用平臺無關(guān)的getaddrinfo()系統(tǒng)函數(shù)實現(xiàn)。2.代理操作系統(tǒng)的DNS處理方法,這種方法正在被Chrome自行實現(xiàn)的一套異步DNS解 析機制(asynchronous DNS resolver)所取代。

依賴于系統(tǒng)的實現(xiàn),代碼少而 且簡單,但是getaddrInfo()是一個阻塞式的系統(tǒng)調(diào)用,無法有效地并行多個查詢操作。經(jīng)驗數(shù)據(jù)還顯示,并行請求過多甚至?xí)雎酚善鞯呢?fù)額。 Chrome為此設(shè)計了一個復(fù)雜的機制。對于其中帶有worker-pool的預(yù)解析, Chrome只是簡單的發(fā)送getaddrinfo() 調(diào)用, 同時阻塞worker thread直到收到響應(yīng)數(shù)據(jù)。因為系統(tǒng)有DNS緩存的原因,針對解析過的主機,解析操作會立即返回。 這個過程簡單,有效。

但還不夠! getaddrinfo()隱藏了太多有用的信息,比如Time-to-live(TTL)時間戳, DNS緩存的狀態(tài)等。于是Chrome決定自己實現(xiàn)一套跨平臺的異步DNS解析器。

1120131107095639

這個新技術(shù)可以支持以下優(yōu)化:

  • 更好地控制重轉(zhuǎn)的時機,有能力并行執(zhí)行多個查詢操作。 清晰地記錄TTLs。
  • 更好地處理IPv4和IPv6的兼容。

基于RTT和其它事件,針對不同服務(wù)器進行錯誤處理(failover)

Chrome仍然進行著持續(xù)的優(yōu)化. 通過chrome://histograms/DNS可以觀察到DNS度量數(shù)據(jù):

1220131107095646

上面的柱狀圖展示了 DNS預(yù)解析延遲時間的分布:比如將近50%(最右側(cè))的查詢在20ms內(nèi)完成。這些數(shù)據(jù)基于最近的瀏覽操作(采樣9869次),用戶可以選擇是否報告這 些使用數(shù)據(jù),然后這些數(shù)據(jù)會以匿名的形式交由工程團隊加以分析,這樣就可以了解到功能的性能,以及未來如何進一步調(diào)整。周而復(fù)始,不斷優(yōu)化。

使用預(yù)連接優(yōu)化了TCP連接管理

已經(jīng)預(yù)解析到了主機名,也有了 由OmniBox和Chrome Predictor提供信號,預(yù)示著用戶未來的操作。為什么再進一步連接到目標(biāo)主機,在用戶真正發(fā)起請求前完成TCP握手呢?這樣就可省掉了另一個往返的 延遲,輕易地就能為用戶節(jié)省到上百毫秒。其實,這就是TCP預(yù)連接的工作。 通過訪問chrome://dns 就可以看到TCP預(yù)連接的使用情況。

1320131107095653

首先, Chrome檢查它的socket pool里有沒有目標(biāo)主機可以復(fù)用的socket, 這些sockets會在socket pool里保留一段時間,以節(jié)省TCP握手時間及啟動延時(slow-start penalty)。如果沒有可用的socket, 就需要發(fā)起TCP握手,然后放到socket pool中。這樣當(dāng)用戶發(fā)起請求時,就可以用這個socket立即發(fā)起HTTP請求。

打開 chrome://net-internals#sockets 就可以看到當(dāng)前的sockets的狀態(tài):

1420131107095702

你可以看到每一個socket的時間軸:連接和代理的時間,每個封包到達的時間,以及其它一些信息。你也可以把這些數(shù)據(jù)導(dǎo)出,以方便進一步分析或者報告問題。有好的測試數(shù)據(jù)是優(yōu)化的基礎(chǔ), chrome://net-internals就是Chrome網(wǎng)絡(luò)的信息中心。

使用預(yù)加載優(yōu)化資源加載

Chrome支持在頁面的HTML標(biāo)簽中加入的兩個線索來優(yōu)化資源加載:

在rel中指定的 subresource(子資源)和prefetch(預(yù)加載)非常相似。不同的是,如果一個link指定rel(relation)為prefetch 后,就是告訴瀏覽器這個資源是稍后的頁面中要用到的。而指定為subresource則表示在本頁中就會用到,期望能在使用前加載。兩者不同的語義讓 resource loader有不同的行為。prefetch的優(yōu)先級較低,一般只會在頁面加載完成后才會開始。而subresource則會在解析出來時就被嘗試優(yōu)先執(zhí) 行。

還要注意,prefetch是HTML5的一部分,F(xiàn)irefox和Chrome都可以支持。但subresource還只能用在Chrome 中。

應(yīng)用Browser Prefreshing優(yōu)化資源加載

不過,并不是所有的Web開發(fā)者會愿意加入上面所述的subresource relation, 就算加了,也要等收到主文檔并解析出這些內(nèi)容才行,這段時間開銷依賴于服務(wù)器的響應(yīng)時間和客戶端與服務(wù)器間的延遲時間,甚至要耗去上千毫秒。

和前面的預(yù)解析,預(yù)連接一樣,這里還有一個prefreshing::

用戶初始化一個目標(biāo)頁面的請求。 Chrome查詢Predictor之前針對目標(biāo)頁面的子資源加載,初始化一組DNS預(yù)解析,TCP預(yù)連接及資源prefreshing。

如是在緩存中發(fā)現(xiàn)之前記錄的子資源,由從磁盤中加載到內(nèi)存中。如果沒有或者已經(jīng)過期了,就是發(fā)送網(wǎng)絡(luò)請求。

[[89150]]

直到在2013年初, prefreshing還是處于早期的討論階段。如果通過數(shù)據(jù)結(jié)果分析,這個功能最終上線了,我們就可以稍晚些時候使用到它了。

#p#

使用預(yù)渲染優(yōu)化頁面瀏覽

前面討論的每個優(yōu)化都用來幫助減少用戶發(fā)起請求到看到頁面內(nèi)容的延遲時間。多快才能帶來即時呈現(xiàn)的體驗?zāi)??基于用戶體驗數(shù)據(jù),這個時間是100毫秒,根本沒給網(wǎng)絡(luò)延遲留什么空間。而在100毫秒內(nèi),又怎樣渲染頁面呢?

大家可能都有這樣的體驗: 同時開多個頁簽時會明顯快于在一個頁簽中等待。瀏覽器為此提供了一個實現(xiàn)方式:

這就是Chrome的預(yù)渲染(prerendering in Chrome)! 相對于只下載一個資源的“prefetch”, “prerender”會讓Chrome在一個不可見的頁簽中渲染一個頁面,包含了它所有的子資源。當(dāng)用戶要瀏覽它時,這個頁簽被切到前臺,做到了即時的 體驗。

可以瀏覽 prerender-test.appspot.com 來體驗一下效果,再通過chrome://net-internals/#prerender查看下歷史記錄和預(yù)連接頁面的狀態(tài)。

1620131107095729

因為預(yù)渲染會同時消耗CPU和網(wǎng)絡(luò)資源,因些一定要在確信預(yù)渲染頁面會被使用到情況下才用。Google Search就在它的搜索結(jié)果里加入prerender, 因為第一個搜索結(jié)果很可能就是下一個頁面(也叫作Google Instant Pages)

你可以使用預(yù)渲染特性,但以下限制項一定要牢記:

.所有的進程中最多只能有一個預(yù)渲染頁。 HTTPS和帶有HTTP認(rèn)證的頁面不可以預(yù)渲染。

.如果請求資源需要發(fā)起非冪等(non-idempotent,idempotent request的意義為發(fā)起多次,不會帶來服務(wù)的負(fù)面響應(yīng)的請求)的請求(只有GET請求)時,預(yù)渲染也不可用。

  • .所有的資源的優(yōu)先級都很低。
  • .頁面渲染進程的使用最低的CPU優(yōu)先級。
  • .如果需要超過100MB的內(nèi)存,將無法使用預(yù)渲染。
  • .不支持HTML5多媒體元素。

預(yù)渲染只能應(yīng)用于確信安全的頁面。另外JavaScript也最好在運行時使用Page Visibility API 來判斷一下當(dāng)前頁是否可見(參考 you should be doing anyway) !

[[89151]]

最后,總之,Chrome正逐步優(yōu)化網(wǎng)絡(luò)延遲和用戶體驗,讓它隨著用戶的使用越來越快!

原文鏈接:http://tech.uc.cn/?p=2092

責(zé)任編輯:陳四芳 來源: UC技術(shù)博客
相關(guān)推薦

2021-05-08 15:20:35

Chrome瀏覽器通知

2023-11-01 11:59:13

2025-01-06 00:00:10

2012-05-08 13:36:55

2009-10-26 09:49:53

Google Chrome OS泄露版

2017-11-28 17:14:16

華為云

2009-06-04 09:20:45

2024-03-18 13:43:20

Linux架構(gòu)

2023-10-31 18:52:29

網(wǎng)絡(luò)框架XDP技術(shù)

2020-06-17 16:43:40

網(wǎng)絡(luò)IO框架

2009-08-12 17:48:56

存儲高性能計算曙光

2010-05-12 11:08:00

2024-04-28 10:17:30

gnetGo語言

2018-10-08 15:22:36

IO模型

2023-11-01 10:38:46

Linux高性能網(wǎng)絡(luò)編程

2022-03-18 12:39:57

UbuntuChrome

2009-02-20 11:04:48

GoogleChrome2.0.164.0

2009-03-01 21:38:04

GoogleChrome 2.0.Beta

2009-03-23 09:01:37

GoogleChrome瀏覽器

2025-01-26 15:44:29

點贊
收藏

51CTO技術(shù)棧公眾號