浏览器预连接性能测试
通過預連接,可以提升用戶訪問體驗,并減少服務器性能消耗。本文來自Akamai 網絡性能業務部門架構師Utkarsh Goel,他展示了一系列對比測試。LiveVideoStack對本文進行了摘譯。
文 / Utkarsh Goel
譯 / 王月美
原文 / https://developer.akamai.com/blog/2018/06/25/experiments-with-browser-preconnects/
為什么有此次實驗?
現代Web瀏覽器采用一套性能優化技術來改善用戶的體驗。預連接提示就是這些優化中的一種,它允許瀏覽器發現關鍵主機名,并主動建立連接,以便在不久的將來提供服務請求。在本文中,將討論Akamai基礎架構收集的幾個大型數據集和一些實驗室內所做的實驗,以及從中觀察到的通過預連接提示建立的連接的某些特征。此次工作的主要發現是:
當瀏覽器建立預連接時,連接上的第一個HTTP請求通常會在建立連接后的幾百毫秒內發送,因為預連接發生時,請求可能不可用,因此瀏覽器必須花費時間來分析HTML,并且尋找可以在連接上發送請求的其他資源。
如果連接建立時間和第一個請求發送的時間間隔大于十秒,瀏覽器將關閉連接,從而失去發送預連接提示的目的。 開發人員必須確保在前10秒內使用預連接提示。
偶然的情況下,預連接可能永遠不會用于發送HTTP請求。那該情況下,服務器基礎結構上的CPU負載可能會最小。
介紹
現代網頁利用數十個主機名來下載數百種資源。對于這些資源中的每一個,瀏覽器都會對其TCP高速緩存執行快速查找,以檢查是否已經存在與相關主機名的連接,以及該連接是否可用。如果TCP連接不可用,瀏覽器將對其DNS緩存執行查找,以檢查相關主機名是否存在DNS條目。如果DNS和TCP條目在緩存中均不可用,瀏覽器將執行DNS查找并建立新的TCP連接,然后在需要的地方進行TLS握手。當DNS條目和連接尚不可用時,頁面加載時間可能會增加,尤其是需要加載位于網頁關鍵路徑上的資源時。
為了避免這些預備任務在網頁的關鍵路徑上發生,許多Web開發人員使用preconnect 提示,讓瀏覽器執行DNS查找,并在提示可用時立即與主機建立TCP / TLS會話。一個好的Web開發實踐會在所請求的主頁 HTML的HTTP響應頭中發送preconnect提示,例如
HTTP/1.1 200 OK
Link: <https://www.foundry.systems>; rel=preconnect;??
或者嵌入在HTML中的標簽中
<link rel="preconnect" href="https://www.foundry.systems" />?
以上示例中,只要上述提示可用于支持預連接提示的瀏覽器,瀏覽器就會執行DNS查找并建立與www.foundry.systems的連接,即使沒有待處理的HTTP請求下,也是如此。
接收preconnect提示并不是網絡瀏覽器預先連接到主機名的唯一原因。例如,Chrome有一個內置的預測機制,可以學習用戶導航的網頁結構,并在用戶導航到頁面后立即對各種主機名進行推測性預連接。例如,如果預測器知道用戶以前訪問過頁面https://www.example.com/index.html需要來自img.example.com和css.example.com的資源,則下次用戶導航至相同頁面時,瀏覽器甚至可以在發現要在這些連接上下載的資源之前主動建立與img.example.com和css.example.com的連接。本文中,我將討論通過Web開發人員預連接提示或Web瀏覽器推測性預連接提示建立連接的某些特性。
未使用的Preconnects(預連接)
在某些情況下,主動建立的連接不會被瀏覽器用來發送任何HTTP請求。 可能是因為以下四種情況中的任一種:
1. 預測器建議根據用戶以前的導航來打開與主機的連接,但網頁已更改,而且也不需要主動連接的主機名中的任何資源。
2. HTTP請求被取消,而建立的連接仍未使用。
3. 準備好發送請求并且瀏覽器開始為其建立連接,但是在連接建立完成之前,與同一主機的其他一些連接變為可用并且請求在該連接上進行傳輸。
4. 瀏覽器可能不記得服務器是否支持HTTP/2,因此它以HTTP/1.1方式打開多個并行連接,但在協商HTTP/2后僅使用了其中一個。
未使用的Preconnects(預連接)
鑒于以上針對未使用的預連接的情況,接下來我研究了Chrome(版本64)在閑置一段時間后如何處理此類連接。 出于實驗的目的,我設置了三個測試頁面,來指示瀏覽器預先連接到主機并在不同時間間隔后在該主機上加載資源。
#1
在第一個測試頁https://dev.utkarshgoel.in/preconnect.html中,我在HTML <head>標簽中添加了一個預連接提示,以連接到一個支持HTTP /2的主機www.foundry.systems。請注意,此頁面在HTML中沒有其他內容。我在加載頁面時,在后臺運行Wireshark實例顯示Chrome為www.foundry.systems建立了TCP和TLS握手。我也在后臺chrome://net-internals/#http2進行了捕獲。然而,該連接沒有在網絡內部注冊為HTTP/2連接,并且網絡內部沒有顯示在連接上發送的SETTINGS幀。
#2
在第二個測試頁https://dev.utkarshgoel.in/preconnect_with_delayed_request.html中,在<head>標簽中,我為www.foundry.systems添加了一個preconnect提示以及一個阻止頁面上任何其他JS執行5秒鐘的外部JS。在HTML的body中,我添加了一個帶有空src屬性的 img標記。然后HTML有一個內聯JS,它將圖像的src屬性設置為指向www.foundry.systems的圖像。此實驗的目的是在連接建立好五秒后,從www.foundry.systems加載資源。
在這個實驗中,我發現Wireshark捕獲與之前的實驗類似,Chrome為www.foundry.systems建立了一個TCP和一個TLS會話,但這次net-internals將連接注冊為HTTP/2連接。然而,該連接在建立5秒后出現在net-internals,此時正發送SETTINGS幀。
這次與之前的實驗表明,只有在連接上發送HTTP請求后,Chrome才會發送HTTP/2 SETTINGS幀(因為這標志著HTTP/2連接的開始)。
#3
在第三個測試頁面https://dev.utkarshgoel.in/preconnect_with_delayed_request_12s.html中,我克隆了第二個測試頁面,并修改了外部JS,以阻止任何其他JS執行12秒。與第二個實驗類似,我發現net-internals的連接在12秒后被注冊。然而,在Wireshark捕獲圖中,我觀察到不是一個,而是兩個連接正在建立。如下面的屏幕截圖所示,兩個連接大約間隔12秒:
在為外部JS加載具有不同阻塞值的測試頁面后,我發現Chrome丟棄了在建立后的前10秒內未使用連接的任何連接狀態。在我的實驗中,內聯JS在預連接后12秒加載了圖像,因此因為超過了10秒的限制,所以Chrome建立了一個新的連接。
因此,一個建議是確保當preconnect 提示顯示的目標是消除網頁關鍵路徑中的DNS和TCP / TLS握手時,瀏覽器必須能夠在10秒內發現需要該連接的資源。
實驗中的另一個觀察是,即使當客戶端第一次連接到服務器時,服務器發送了TLS會話票據;當客戶端第二次連接服務器時,客戶端也不會在其clientHello中公布會話票據。要觀察此情況,請查看下面屏幕截圖中的第二個紅色框,突出顯示clientHello中公布的會話票證的大小。
#4
上述實驗操作促使我設置了第四個實驗,在測試頁面(https://dev.utkarshgoel.in/preconnect_with_repeated_delayed_requests.html)中,我克隆了第三個測試頁面,并在HTML body中添加了外部JS和內聯JS 。第二個外部JS的目的是阻止第二個內聯JS執行額外的70秒,因為這是我發現Chrome通過net-internals終止先前的HTTP /2連接所花費的時間。總結一下,頁面加載的流程如下:
HTML load -> Preconnect -> wait 12 seconds -> Reconnect -> load image -> wait 70+ seconds -> Reconnect -> load image
如上方的屏幕截圖所示,運行這樣的實驗會導致建立三個連接。在Wireshark捕獲中,我看到Chrome僅在第三個clientHello(如紅色框中所示)中公布了會話票證。這表明只有在上一次在連接上發送HTTP請求時,會話票證才從緩沖區中拉出/傳遞到上層。
未使用連接產生的通信流量
在了解了Chrome主動打開的連接的上述特征之后,我好奇服務器在接收未用于提供任何HTTP請求的連接請求的頻率大小。這是非常重要的,因為如果瀏覽器打開太多這樣的連接,則可能會給服務器帶來太多的負擔。對于每個TLS會話,無論是否提供請求,服務器都必須執行CPU密集型公鑰加密操作。為了找到上述問題的答案,我研究了建立在Akamai分布式基礎設施上的用于內容傳送的超過170萬個TCP連接的統計數據。最后,我發現多達6%的TLS連接從不用于HTTP請求。
使用預連接
雖然在少數情況下主動建立的連接不被使用,但在大多數情況下,這些連接還是用于提供HTTP請求的。但是,由于預連接發生在頁面導航的早期,并且瀏覽器可能需要一段時間才能發現連接上發送的請求,所以我也有興趣來研究連接建立完成時和第一個HTTP請求到達服務器之間的時間間隔。
這個時間間隔將告訴我們主動建立的連接在建立之后仍然閑置的時間長度。
圖1.在不同主機名中觀察到的時間間隔的箱形圖分布。 為了觀察清晰,我只繪制了200個主機名的圖。
使用的預連接:實驗情況
在此分析中,我使用了500多個Akamai邊緣服務器來收集Chrome瀏覽器通過HTTP/2連接生成的,超過730萬個HTTP請求的統計信息。圖1中的x軸顯示了在200個主機名中觀察到的時間間隔分布。y軸以毫秒為單位顯示時間間隔。如圖所示,在主動建立的連接上,在連接建立后的中值情況下,第一個HTTP請求可能會在四秒內到達服務器。但是,對于大多數主機名,第一個請求在連接建立結束后大約50毫秒內到達。如此大的時間間隔相當于有線寬帶網絡中的多次往返以及少快速移動網絡中更少的往返次數。此外,我發現此行為僅適用于與嵌入在HTML中的子資源關聯的主機名。
此外,由于HTTP/2協議不允許服務器在客戶端在連接上發出第一個請求之前推送任何內容,因此服務器缺乏對此類時間間隙采取行動來改進性能的能力。從理論上講,人們可以利用實驗性的未綁定服務器推送方案,在連接空閑時來推送關鍵資源。 但是,如上一節所示,Chrome無法讀取這些空閑連接上傳入的數據,因此,如果不更改Chrome處理網絡套接字的方式,則無法使用該技術。
結論
雖然此項研究有許多次要和主要的發現,但我會強調一些我認為對于web開發人員來說最重要的:
由于預先連接提示被公布來消除來自網頁關鍵路徑的耗時的DNS查找和TCP/TLS握手,所以當開發網頁時,我們應該確保在前10秒內使用該連接。簡而言之,確保網站沒有可能阻止瀏覽器發現需要這些預連接資源的JS。確保將您的網站性能與無預連接提示進行比較,以驗證該提示不會影響性能。
服務器上未使用的連接會產生額外的CPU負載。本文中,我討論了一種減少此負載的方法。
對于與HTML上的子資源相關聯的大多數主機名建立的連接,連接在建立完成后仍保持約50毫秒空閑。提交給IETF的實驗性未綁定服務器推送方案可能是利用連接保持空閑的時間的一種方式。
Utkarsh Goel是Akamai 網絡性能業務部門的架構師,他喜歡通過使用構建技術來改善Web性能的當前狀態。他還是Akamai Foundry的成員,并專注于探索新【技術以改善各種形式的互聯網性能。
感謝Akamai的Mike Bishop,Moritz Steiner和Stephen Ludin為本文的早期版本提供了一些研究思路和反饋意見。
總結
以上是生活随笔為你收集整理的浏览器预连接性能测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 音视频技术开发周刊 56期
- 下一篇: LiveVideoStackCon讲师热