web性能監(jiān)控及采集方式

也許你有聽過一個問題,你這款 web 應(yīng)用性能怎么樣呀?你會回答什么呢?是否會優(yōu)于海量 web 應(yīng)用市場呢?本文就來整理下如何進行 web 性能監(jiān)控?包括我們需要監(jiān)控的指標、監(jiān)控的分類、performance 分析以及如何監(jiān)控。

但是,如何進行 web 性能監(jiān)控本身是一個很大的話題,文中只會側(cè)重一部分進行研究,某些內(nèi)容不是很全面。

前言:為什么需要監(jiān)控?

web 的性能一定程度上影響了用戶留存率,Google DoubleClick 研究表明:如果一個移動端頁面加載時長超過 3 秒,用戶就會放棄而離開。BBC 發(fā)現(xiàn)網(wǎng)頁加載時長每增加 1 秒,用戶就會流失 10%。

我們希望通過監(jiān)控來知道 web 應(yīng)用性能的現(xiàn)狀和趨勢,找到 web 應(yīng)用的瓶頸?某次發(fā)布后的性能情況怎么樣?是否發(fā)布后對性能有影響?感知到業(yè)務(wù)出錯的概率?業(yè)務(wù)的穩(wěn)定性怎么樣?

監(jiān)控什么?

首先我們需要知道應(yīng)該監(jiān)控些什么呢?有哪些具體的指標?

google 開發(fā)者提出了一種 RAIL 模型來衡量應(yīng)用性能,即:ResponseAnimation、Idle、Load,分別代表著 web 應(yīng)用生命周期的四個不同方面。并指出最好的性能指標是:100ms 內(nèi)響應(yīng)用戶輸入;動畫或者滾動需在 10ms 內(nèi)產(chǎn)生下一幀;最大化空閑時間;頁面加載時長不超過 5 秒。

image

我們可轉(zhuǎn)化為三個方面來看:響應(yīng)速度、頁面穩(wěn)定性、外部服務(wù)調(diào)用

  • 響應(yīng)速度:頁面初始訪問速度 + 交互響應(yīng)速度
  • 頁面穩(wěn)定性:頁面出錯率
  • 外部服務(wù)調(diào)用:網(wǎng)絡(luò)請求訪問速度

1.頁面訪問速度:白屏、首屏?xí)r間、可交互時間

我們來看看 google 開發(fā)者針對用戶體驗,提出的幾個性能指標

image

這幾個指標其實都是根據(jù)用戶體驗,提煉出對應(yīng)的性能指標

image

1)first paint (FP) and first contentful paint (FCP)

首次渲染、首次有內(nèi)容的渲染

這兩個指標瀏覽器已經(jīng)標準化了,從 performance 的 The Paint Timing API 可以獲取到,一般來說兩個時間相同,但也有情況下兩者不同。

image

2)First meaningful paint and hero element timing

首次有意義的渲染、頁面關(guān)鍵元素

我們假設(shè)當一個網(wǎng)頁的 DOM 結(jié)構(gòu)發(fā)生劇烈的變化的時候,就是這個網(wǎng)頁主要內(nèi)容出現(xiàn)的時候,那么在這樣的一個時間點上,就是首次有意義的渲染。這個指標瀏覽器還沒有規(guī)范,畢竟很難統(tǒng)一一個標準來定義網(wǎng)站的主體內(nèi)容。

google lighthouse 定義的 first meaningful painthttps://docs.google.com/document/d/1BR94tJdZLsin5poeet0XoTW60M0SjvOJQttKT-JK8HI/view

3)Time to interactive

可交互時間

4)長任務(wù)

瀏覽器是單線程的,如果長任務(wù)過多,那必然會影響著用戶響應(yīng)時長。好的應(yīng)用需要最大化空閑時間,以保證能最快響應(yīng)用戶的輸入。

image

2.頁面穩(wěn)定性:頁面出錯情況

  • 資源加載錯誤
  • JS 執(zhí)行報錯

3.外部服務(wù)調(diào)用

  • CGI 耗時
  • CGI 成功率
  • CDN 資源耗時

監(jiān)控的分類?

web 性能監(jiān)控可分為兩類,一類是合成監(jiān)控(Synthetic Monitoring,SYN),另一類是真實用戶監(jiān)控(Real User Monitoring,RUM)

合成監(jiān)控

合成監(jiān)控是采用 web 瀏覽器模擬器來加載網(wǎng)頁,通過模擬終端用戶可能的操作來采集對應(yīng)的性能指標,最后輸出一個網(wǎng)站性能報告。例如:Lighthouse、PageSpeed、WebPageTest、Pingdom、PhantomJS 等。

1. Lighthouse

Lighthouse 是 google 一個開源的自動化工具,運行 Lighthouse 的方式有兩種:一種是作為 Chrome 擴展程序運行;另一種作為命令行工具運行。Chrome 擴展程序提供了一個對用戶更友好的界面,方便讀取報告。通過命令行工具可以將 Lighthouse 集成到持續(xù)集成系統(tǒng)。

展示了白屏、首屏、可交互時間等性能指標和 SEO、PWA 等。

騰訊文檔移動端官網(wǎng)首頁測速結(jié)果:

image

2. PageSpeed

https://developers.google.com/speed/pagespeed/insights/

不僅展示了一些主要的性能指標數(shù)據(jù),還給出了部分性能優(yōu)化建議。

騰訊文檔移動端首頁測速結(jié)果和性能優(yōu)化建議:

image

3. WebPageTest

WebPageTest

給出性能測速結(jié)果和資源加載的瀑布圖。

image

4. Pingdom

https://www.pingdom.com/

注意:Pingdom 不僅提供合成監(jiān)控,也提供真實用戶監(jiān)控。

image

合成監(jiān)控方式的優(yōu)缺點:

優(yōu)點:

  • 無侵入性。
  • 簡單快捷。缺點:
  • 不是真實的用戶訪問情況,只是模擬的。
  • 沒法考慮到登錄的情況,對于需要登錄的頁面就無法監(jiān)控到。

二、真實用戶監(jiān)控

真實用戶監(jiān)控是一種被動監(jiān)控技術(shù),是一種應(yīng)用服務(wù),被監(jiān)控的 web 應(yīng)用通過 sdk 等方式接入該服務(wù),將真實的用戶訪問、交互等性能指標數(shù)據(jù)收集上報、通過數(shù)據(jù)清洗加工后形成性能分析報表。例如 FrontJs、oneapm、Datadog 等。

image

1. oneapm

https://www.oneapm.com/bi/feature.html

功能包括:大盤數(shù)據(jù)、特征統(tǒng)計、慢加載追蹤、訪問頁面、腳本錯誤、AJAX、組合分析、報表、告警等。

image

2. Datadog

https://www.datadoghq.com/rum/

image

3. FrontJs

https://www.frontjs.com/

功能包括:訪問性能、異常監(jiān)控、報表、趨勢等。
image

這種監(jiān)控方式的優(yōu)缺點:

優(yōu)點:

  • 是真實用戶訪問情況。
  • 可以觀察歷史性能趨勢。
  • 有一些額外的功能:報表推送、監(jiān)控告警等等。缺點:
  • 有侵入性,會一定程度上響應(yīng) web 性能。

performance 分析

在講如何監(jiān)控之前,先來看看瀏覽器提供的 performance api,這也是性能監(jiān)控數(shù)據(jù)的主要來源。

performance 提供高精度的時間戳,精度可達納秒級別,且不會隨操作系統(tǒng)時間設(shè)置的影響。

目前市場上的支持情況:主流瀏覽器都支持,大可放心使用。

image

基本屬性

performance.navigation: 頁面是加載還是刷新、發(fā)生了多少次重定向
image

performance.timing: 頁面加載的各階段時長

image

各階段的含義:

image

performance.memory:基本內(nèi)存使用情況,Chrome 添加的一個非標準擴展

image

performance.timeorigin: 性能測量開始時的時間的高精度時間戳

image

基本方法

performance.getEntries()

通過這個方法可以獲取到所有的 performance 實體對象,通過 getEntriesByNamegetEntriesByType 方法可對所有的 performance 實體對象 進行過濾,返回特定類型的實體。

mark 方法 和 measure 方法的結(jié)合可打點計時,獲取某個函數(shù)執(zhí)行耗時等。

image
  • performance.getEntriesByName()
  • performance.getEntriesByType()
  • performance.mark()
  • performance.clearMarks()
  • performance.measure()
  • performance.clearMeasures()
  • performance.now() ...

提供的 API

performance 也提供了多種 API,不同的 API 之間可能會有重疊的部分。

1. PerformanceObserver API

用于檢測性能的事件,這個 API 利用了觀察者模式。

獲取資源信息
image

監(jiān)測 TTI
image

監(jiān)測 長任務(wù)
image

2. Navigation Timing API

https://www.w3.org/TR/navigation-timing-2/

performance.getEntriesByType("navigation");

image
image

不同階段之間是連續(xù)的嗎? —— 不連續(xù)

每個階段都一定會發(fā)生嗎?—— 不一定

  • 重定向次數(shù):performance.navigation.redirectCount
  • 重定向耗時: redirectEnd - redirectStart
  • DNS 解析耗時: domainLookupEnd - domainLookupStart
  • TCP 連接耗時: connectEnd - connectStart
  • SSL 安全連接耗時: connectEnd - secureConnectionStart
  • 網(wǎng)絡(luò)請求耗時 (TTFB): responseStart - requestStart
  • 數(shù)據(jù)傳輸耗時: responseEnd - responseStart
  • DOM 解析耗時: domInteractive - responseEnd
  • 資源加載耗時: loadEventStart - domContentLoadedEventEnd
  • 首包時間: responseStart - domainLookupStart
  • 白屏?xí)r間: responseEnd - fetchStart
  • 首次可交互時間: domInteractive - fetchStart
  • DOM Ready 時間: domContentLoadEventEnd - fetchStart
  • 頁面完全加載時間: loadEventStart - fetchStart
  • http 頭部大?。簍ransferSize - encodedBodySize

3. Resource Timing APIhttps://w3c.github.io/resource-timing/

performance.getEntriesByType("resource");

image
image

image.png
// 某類資源的加載時間,可測量圖片、js、css、
XHRresourceListEntries.forEach(resource => {   
 if (resource.initiatorType == 'img') {   
 console.info(`Time taken to load ${resource.name}: `, resource.responseEnd - resource.startTime);    
}});

這個數(shù)據(jù)和 chrome 調(diào)式工具里 network 的瀑布圖數(shù)據(jù)是一樣的。

4. paint Timing API

https://w3c.github.io/paint-timing/

首屏渲染時間、首次有內(nèi)容渲染時間
image

5. User Timing API

https://www.w3.org/TR/user-timing-2/#introduction

主要是利用 mark 和 measure 方法去打點計算某個階段的耗時,例如某個函數(shù)的耗時等。

<head>
<script>
    // 通常在head標簽尾部時,打個標記,這個通常會視為白屏?xí)r間
    performance.mark("first paint time");
</script>
</head>
<body>
...
<script>
    // get the first paint time
    const fp = Math.ceil(performance.getEntriesByName('first paint time')[0].startTime);
</script>
</body> 

6. High Resolution Time APIhttps://w3c.github.io/hr-time/#dom-performance-timeorigin

主要包括 now() 方法和 timeOrigin 屬性。

7. Performance Timeline APIhttps://www.w3.org/TR/performance-timeline-2/#introduction

總結(jié)

基于 performance 我們可以測量如下幾個方面:

mark、measure、navigation、resource、paint、frame。

let p = window.performance.getEntries();

重定向次數(shù):performance.navigation.redirectCount

JS 資源數(shù)量: p.filter(ele => ele.initiatorType === "script").length

CSS 資源數(shù)量:p.filter(ele => ele.initiatorType === "css").length

AJAX 請求數(shù)量:p.filter(ele => ele.initiatorType === "xmlhttprequest").length

IMG 資源數(shù)量:p.filter(ele => ele.initiatorType === "img").length

總資源數(shù)量: window.performance.getEntriesByType("resource").length

不重復(fù)的耗時時段區(qū)分:

  • 重定向耗時: redirectEnd - redirectStart
  • DNS 解析耗時: domainLookupEnd - domainLookupStart
  • TCP 連接耗時: connectEnd - connectStart
  • SSL 安全連接耗時: connectEnd - secureConnectionStart
  • 網(wǎng)絡(luò)請求耗時 (TTFB): responseStart - requestStart
  • HTML 下載耗時:responseEnd - responseStart
  • DOM 解析耗時: domInteractive - responseEnd
  • 資源加載耗時: loadEventStart - domContentLoadedEventEnd

其他組合分析:

  • 白屏?xí)r間: domLoading - fetchStart
  • 粗略首屏?xí)r間: loadEventEnd - fetchStart 或者 domInteractive - fetchStart
  • DOM Ready 時間: domContentLoadEventEnd - fetchStart
  • 頁面完全加載時間: loadEventStart - fetchStart

JS 總加載耗時:

const p = window.performance.getEntries();
let cssR = p.filter(ele => ele.initiatorType === "script");
Math.max(...cssR.map((ele) => ele.responseEnd)) - Math.min(...cssR.map((ele) => ele.startTime));

CSS 總加載耗時:

const p = window.performance.getEntries();
let cssR = p.filter(ele => ele.initiatorType === "css");
Math.max(...cssR.map((ele) => ele.responseEnd)) - Math.min(...cssR.map((ele) => ele.startTime));

npm install -g lighthouse

image.png

當頁面鏈接至使用 target="_blank" 的另一個頁面時,兩個頁面將在同一個進程上運行。 如果新頁面正在執(zhí)行開銷極大的 JavaScript,當前頁面性能可能會受影響。
另外,target="_blank" 也有一個安全漏洞。新的頁面可以通過 window.opener 訪問舊的窗口對象,甚至可以使用 window.opener.location = newURL 將舊頁面導(dǎo)航至不同的網(wǎng)址。

當設(shè)置rel="noopener"時chrome會在獨立的進程中打開新頁面,同時會阻止window.opener,因此不存在跨窗口訪問。

  <a target="_blank" rel="noopener" >

image.png

轉(zhuǎn)原文:騰訊前端團隊是如何做web性能監(jiān)控的?https://mp.weixin.qq.com/s/y2jh7oT36XdmHM9fImLl_w

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容