汽車(chē)之家頁(yè)面性能監(jiān)控建設(shè)實(shí)踐

一、前言
關(guān)注用戶(hù)體驗(yàn),提高頁(yè)面性能,是每位前端研發(fā)同學(xué)的日常工作之一。提高頁(yè)面性能對(duì)業(yè)務(wù)的幫助,雖不易衡量,但肯定是利遠(yuǎn)大于弊。如何衡量頁(yè)面性能優(yōu)劣?如何幫助研發(fā)同學(xué)快速定位到頁(yè)面性能瓶頸點(diǎn)?一直是前端的重點(diǎn)工作之一。本文分享汽車(chē)之家在頁(yè)面性能監(jiān)控建設(shè)方面的部分工作,主要包含三方面:
技術(shù)選型
- 該選擇哪些頁(yè)面性能監(jiān)控技術(shù)方案?
- 在盡可能不影響頁(yè)面性能的前提下,既能客觀、全面衡量頁(yè)面性能,又能幫助研發(fā)同學(xué)快速定位性能瓶頸點(diǎn),該采集哪些指標(biāo)?
- SPA 應(yīng)用非首頁(yè)性能該如何評(píng)估?
- 在盡可能不影響頁(yè)面性能和保證采集數(shù)據(jù)精準(zhǔn)性的前提下,盡量多地采集和上報(bào)數(shù)據(jù),如何選擇合適的指標(biāo)采集時(shí)機(jī)和上報(bào)方式?
整體架構(gòu)設(shè)計(jì)
整合選中技術(shù)方案,構(gòu)建體系化性能監(jiān)控架構(gòu),提供性能監(jiān)控和性能分析工具鏈,支持產(chǎn)研同學(xué)在 DevOps 各階段中發(fā)現(xiàn)和定位頁(yè)面性能問(wèn)題。
建立評(píng)判體系
有數(shù)據(jù),我們才能度量;有評(píng)分,技術(shù)才好改進(jìn)。
利用采集到的眾多指標(biāo),根據(jù)應(yīng)用特性,按各性能指標(biāo)的重要程度,設(shè)置不同的基線和權(quán)重,以加權(quán)平均的方式,求得應(yīng)用得分。通過(guò)分?jǐn)?shù),直觀告訴研發(fā)同學(xué)應(yīng)用頁(yè)面快或慢?應(yīng)用性能高或低?是否需要改進(jìn)?
應(yīng)用得分只能反映單個(gè)應(yīng)用的性能情況,主要服務(wù)于產(chǎn)研同學(xué)。一家公司有多個(gè)部門(mén),每個(gè)部門(mén)有多個(gè)團(tuán)隊(duì),一個(gè)團(tuán)隊(duì)有多個(gè)應(yīng)用,我們需要公司、部門(mén)和團(tuán)隊(duì)層級(jí)的性能得分,才能讓各級(jí)領(lǐng)導(dǎo)直觀了解其負(fù)責(zé)隊(duì)伍的頁(yè)面性能,也方便上級(jí)領(lǐng)導(dǎo)判斷下級(jí)各隊(duì)伍之間的性能高低,所以我們根據(jù)應(yīng)用 PV 數(shù)和應(yīng)用級(jí)別,仍以加權(quán)平均算法,獲得團(tuán)隊(duì)、部門(mén)和公司性能得分。
二、技術(shù)選型
根據(jù)監(jiān)控頁(yè)面性能時(shí)的運(yùn)行環(huán)境,我們將技術(shù)方案分為兩種:合成監(jiān)控(Synthetic Monitoring,SYN)和真實(shí)用戶(hù)監(jiān)控(Real User Monitoring,RUM)。
合成監(jiān)控 (以下簡(jiǎn)稱(chēng) SYN)
指在通過(guò)仿真環(huán)境運(yùn)行頁(yè)面,評(píng)估頁(yè)面性能。早期代表工具有我們熟知的 YSlow 和 PageSpeed。隨著技術(shù)進(jìn)步,當(dāng)前三個(gè)最成熟的 SYN 工具為:Lighthouse、WebPageTest 和 SiteSpeed。Lighthouse 雖然僅支持 Chrome 瀏覽器、實(shí)施成本較高,但是有谷歌支持、易擴(kuò)展、指標(biāo)豐富、有評(píng)分諸多優(yōu)勢(shì),已逐步代替 WebPageTest,成為 SYN 首選工具。 如下以 Lighthouse 為例介紹 SYN 的運(yùn)行過(guò)程、優(yōu)缺點(diǎn)。
運(yùn)行過(guò)程

從運(yùn)行結(jié)果頁(yè)面來(lái)看,Lighthouse 除了輸出關(guān)鍵性能指標(biāo)值和評(píng)分外,還向我們提供優(yōu)化建議和診斷結(jié)果。10.1.0 版 Lighthouse 分別內(nèi)置 94、16 條性能和最佳實(shí)踐方面的規(guī)范或建議,其中不乏日常研發(fā)比少留意且較有意義的規(guī)范,如:最大限度地減少主線程工作(mainthread-work-breakdown)、網(wǎng)頁(yè)已阻止恢復(fù)往返緩存(bf-cache)、減少 js 文件中未使用的 JavaScript (unused-javascript)等。
推薦使用 Node Cli 或 Node Module 方式運(yùn)行 Lighthouse,同時(shí)輸出 html 和 json 格式的結(jié)果。json 中數(shù)據(jù)更全面,包含如:最大內(nèi)容渲染時(shí)間元素(largest-contentful-paint-element)、應(yīng)避免出現(xiàn)長(zhǎng)時(shí)間運(yùn)行的主線程任務(wù)(long-tasks)等明細(xì)信息。
優(yōu)缺點(diǎn)
根據(jù)我們實(shí)踐,總結(jié) Lighthouse 有如下優(yōu)缺點(diǎn):

改進(jìn)
針對(duì)上述不足和產(chǎn)品需求,我們做了一些改進(jìn):
n 為解決 默認(rèn)無(wú)基準(zhǔn)環(huán)境,相同頁(yè)面在不同用戶(hù)端運(yùn)行,因運(yùn)行環(huán) 境和硬件資源不同,導(dǎo)致結(jié)果不同 的問(wèn)題,我們做了兩方面的改進(jìn):
首先,提供 SYN 基準(zhǔn)運(yùn)行環(huán)境。利用 Lighthouse Node Module 自研 Web 版 SYN 服務(wù)并部署在容器中。通過(guò)在 Node 服務(wù)端添加隊(duì)列策略,保證單容器任意時(shí)間只允許運(yùn)行一個(gè) SYN 任務(wù),且每個(gè)容器的硬件資源( 4 核 + 4G )和網(wǎng)速配置( M 端應(yīng)用統(tǒng)一使用 10M 網(wǎng)速 )都一樣,從而保證運(yùn)行結(jié)果和最終得分是相對(duì)公平和可靠的。

其次,支持以計(jì)劃任務(wù),間隔 6、12 或 24 小時(shí) 的方式運(yùn)行 SYN 任務(wù)。 統(tǒng)計(jì)多次運(yùn)行結(jié)果指標(biāo)的 AVG、TP 值,排除少數(shù)異常運(yùn)行的結(jié)果偏差。

- 針對(duì) 運(yùn)行慢,占用資源多 的問(wèn)題。我們認(rèn)為相同頁(yè)面,如果沒(méi)有改版,沒(méi)必要過(guò)于頻繁的持續(xù)測(cè)試,建議 PV 量大或重要頁(yè)面添加計(jì)劃任務(wù) 12 小時(shí)及以上時(shí)間間隔運(yùn)行一次,這樣既能客觀反映頁(yè)面性能情況,也能節(jié)省資源。
- 將 SYN 集成到 CI 流水線中,將 SYN 作為上線前頁(yè)面性能測(cè)試或競(jìng)品對(duì)比的實(shí)施工具。

適用場(chǎng)景
- 將 SYN 作為頁(yè)面性能測(cè)試工具,集成到前端監(jiān)控后臺(tái)應(yīng)用、QA 套件 和 CI 中。建議研發(fā)同學(xué)交付頁(yè)面前,通過(guò) SYN 評(píng)估頁(yè)面性能并根據(jù)優(yōu)化建議和診斷結(jié)果,改進(jìn)頁(yè)面質(zhì)量缺陷,提高交付質(zhì)量。
- 利用 SYN 做競(jìng)品對(duì)比。
- 將 SYN 作為分析 RUM 捕獲到慢頁(yè)面的首選工具,結(jié)合 Chrome DevTools , 從實(shí)踐來(lái)看可以定位到多數(shù)問(wèn)題。
使用方法

總結(jié)
SYN 實(shí)施成本低,便于統(tǒng)一標(biāo)準(zhǔn),相比 RUM,受運(yùn)行時(shí)環(huán)境的影響更小,結(jié)果更具有可比性和可復(fù)現(xiàn)性,是性能監(jiān)控的重要一環(huán)?;?Lighthouse,借助 K8S 等容器編排技術(shù),快速搭建提供基準(zhǔn)環(huán)境的 SYN Web 服務(wù)是建設(shè)頁(yè)面性能監(jiān)控體系的第一階段。該階段以提供評(píng)估頁(yè)面性能、分析慢頁(yè)面等關(guān)鍵功能為主。雖然 Lighthouse 還存在 僅支持谷歌瀏覽器,代表性不足,也不能真實(shí)反映真實(shí)用戶(hù)端的性能情況 這兩個(gè)問(wèn)題,但瑕不掩瑜,可以作為 SYN 的首選方案。同時(shí),這兩個(gè)問(wèn)題我們將通過(guò)添加另外一種技術(shù)方案:真實(shí)用戶(hù)監(jiān)控(RUM)來(lái)解決。
真實(shí)用戶(hù)監(jiān)控 ( 簡(jiǎn)稱(chēng) RUM)
顧名思義,指監(jiān)控運(yùn)行在真實(shí)用戶(hù)終端(瀏覽器),采集用戶(hù)運(yùn)行頁(yè)面時(shí)候真實(shí)的性能指標(biāo)。業(yè)內(nèi)技術(shù)方案主要分為兩種:
依托 W3C 組織且各瀏覽器廠商廣泛支持技術(shù)方案:PerformanceTiming 和 PerformanceNavigationTiming。偏向從瀏覽器處理過(guò)程角度去衡量頁(yè)面運(yùn)行時(shí)各節(jié)點(diǎn)、各階段的耗時(shí)。
各廠根據(jù)實(shí)際需求自研技術(shù)方案。谷歌 web-vitals 是其中最優(yōu)秀的代表,它從用戶(hù)體驗(yàn)角度,用更通俗易懂的指標(biāo)展現(xiàn)頁(yè)面性能。
除上述兩種常見(jiàn)技術(shù)方案外,少數(shù)商業(yè)前端監(jiān)控服務(wù)廠商,除了支持 W3C 和 web-vitals 外,還提供少數(shù)自定義性能指標(biāo),如:阿里 ARMS 中的 FMP 、字節(jié) WebPro 里的 SPA_LOAD 。SPA_LOAD 用于評(píng)估 SPA 非首頁(yè)的頁(yè)面性能,有較大創(chuàng)新性,后面還會(huì)提及。
技術(shù)選型
技術(shù)選型主要解決兩個(gè)問(wèn)題:1)W3C 的 PerformanceTiming 和 PerformanceNavigationTiming 兩規(guī)范,應(yīng)該以哪個(gè)為主?2)W3C Timing 規(guī)范 和 web-vitals 應(yīng)該如何協(xié)作?
W3C 的 PerformanceTiming 和 PerformanceNavigationTiming 兩規(guī)范,應(yīng)該以哪個(gè)為主?
PerformanceTiming:已被最新 W3C 標(biāo)準(zhǔn)廢棄,不過(guò)當(dāng)前主流瀏覽器仍支持,舊瀏覽器支持好,兼容度高。

PerformanceNavigationTiming:最新標(biāo)準(zhǔn)隨 Navigation Timing Level 2 于 2019 年推出,Navigation Timing Level 2 目的是代替涵蓋 PerformaceTiming 的 Navigation Timing Level 1。

變更點(diǎn):
- 整合 PerformanceTiming 和 PerformanceNavigation 功能。
- 廢棄因各瀏覽器廠商實(shí)現(xiàn)不一,指導(dǎo)意義不足的 domLoading 節(jié)點(diǎn)。
- 添加 ServiceWorker 相關(guān)節(jié)點(diǎn)。
- 各屬性節(jié)點(diǎn)時(shí)間使用高精度、以 startTime 為起點(diǎn)的相對(duì)時(shí)間。
優(yōu)點(diǎn):
- 使用高精度的相對(duì)時(shí)間,避免因用戶(hù)端系統(tǒng)時(shí)間更改而導(dǎo)致后續(xù)節(jié)點(diǎn)值不準(zhǔn)。
- 支持 ServiceWorker 相關(guān)統(tǒng)計(jì)。
缺點(diǎn):
- 瀏覽器兼容性不足。
結(jié)論:
從 Can I Use 統(tǒng)計(jì)兩者兼容度僅差 2.67%,但是從我們實(shí)際用戶(hù)分布來(lái)看,使用 PerformanceNavigationTiming,用戶(hù)兼容度下降 12%,難以接受。所以我們以 PerformanceNavigationTiming 為主,如瀏覽器不支持,則使用 PerformanceTiming。兩者數(shù)據(jù)格式差異不大,忽略 PerformanceTiming 中 domLoading 節(jié)點(diǎn),使用 PerformanceTiming 時(shí)認(rèn)為瀏覽器不兼容 workStart 節(jié)點(diǎn)即可。
W3C Timing 規(guī)范 和 web-vitals 應(yīng)該如何協(xié)作?
PerformanceNavigationTiming ( 以下簡(jiǎn)稱(chēng) Timing ): 基于 W3C 規(guī)范,著重從瀏覽器處理過(guò)程角度衡量頁(yè)面性能,以下簡(jiǎn)稱(chēng) Timing。
優(yōu)點(diǎn):
- 瀏覽器兼容性好瀏覽器兼容性好。
- 數(shù)據(jù)豐富,指標(biāo)全面。即包含各階段耗時(shí),如:Unload、Redirect、DNS、TCP、SSL、Response、DomContentLoadedEvent 和 LoadEvent;還支持顯示頁(yè)面運(yùn)行到各節(jié)點(diǎn)時(shí)的耗時(shí),如:workStart、fetchStart、requestStart、domInteractive 和 domComplate;也可以根據(jù)所給節(jié)點(diǎn)值,計(jì)算 DCL ( DomContentLoaded ) 、window.load 事件或者 PageLoad(頁(yè)面加載)的耗時(shí)。
缺點(diǎn):
- 缺乏關(guān)鍵指標(biāo)。雖然指標(biāo)多、全,但是不夠直觀,很難表達(dá)用戶(hù)體驗(yàn)效果。
web-vitals: 目前含 6 個(gè)指標(biāo):TTFB、FCP、LCP、FID、INP 和 CLS,其中 FID 將被 INP 代替。TTFB、FCP 和 LCP 反映頁(yè)面加載性能,F(xiàn)ID 與 INP 代表頁(yè)面交互體驗(yàn),CLS 表示頁(yè)面視覺(jué)穩(wěn)定性。僅 6 個(gè)指標(biāo),就能支持對(duì)頁(yè)面加載、交互和視覺(jué)穩(wěn)定方面的評(píng)估。不過(guò) web-vitals 部分指標(biāo)源頭還是來(lái)自于 W3C 制定的 LargestContentfulPaint、LayoutShift、PerformanceEventTiming 和 PerformancePaintTiming 等規(guī)范,不過(guò)兼容性更好、整體性更強(qiáng)。

優(yōu)點(diǎn):
- 指標(biāo)簡(jiǎn)明、精練、易懂。
- 自帶基線,能根據(jù)指標(biāo),判斷頁(yè)面性能優(yōu)劣。
缺點(diǎn):
- 瀏覽器兼容不足,尤其在 IOS 端。
- LCP 可以偽造。做法:給頁(yè)面添加大尺寸白底圖,該圖加載時(shí)間大概率就是 LCP 值,但是該 LCP 值并沒(méi)有任何業(yè)務(wù)意義
- 受限于 LCP、CLS 原理,對(duì)采集指標(biāo)時(shí)機(jī)有一定要求,后面會(huì)詳細(xì)介紹。
述求
真實(shí)、客觀、全面衡量頁(yè)面性能。
結(jié)論
同時(shí)采集 Timing 和 web-vitals 數(shù)據(jù),帶來(lái)好處有:
- 指標(biāo)豐富、數(shù)據(jù)全面,既能利用 Timing 站在瀏覽器角度反映各節(jié)點(diǎn)、各階段處理耗時(shí),也能通過(guò) web-vitals 直觀表達(dá)用戶(hù)視覺(jué)體驗(yàn)。建議先通過(guò) web-vitals 直觀判斷頁(yè)面性能,再通過(guò) Timing 再進(jìn)一步分析,達(dá)到綜合考慮、全面分析,減少因?yàn)g覽器兼容不足、LCP 造假等情況下,誤判頁(yè)面性能。
- 結(jié)合 Timing 和 web-vitals 數(shù)據(jù),更容易定位問(wèn)題。如:web-vitals 采集到的 TTFB 慢,可以通過(guò) Timing 定位到具體慢在 Unload、Redirect、DNS、TCP、SSL 哪個(gè)階段。
- 解決 web-vitals 老瀏覽器兼容不足的問(wèn)題。如果瀏覽器不支持 web-vitals, 可以通過(guò) DCL、window.load 事件或者 PageLoad(頁(yè)面加載)的耗時(shí)來(lái)判斷頁(yè)面性能。
小節(jié):RUM 技術(shù)選型,同時(shí)采集 PerformanceNavigationTiming 和 web- vitals。如果瀏覽器不兼容 PerformanceNavigationTiming,則以 PerformanceTiming 代替。
采集哪些指標(biāo)
我們的需求是:在盡可能不影響頁(yè)面性能,既能客觀、全面衡量頁(yè)面性能,又能幫助研發(fā)同學(xué)快速定位性能瓶頸點(diǎn)。具體包含三方面需求:1) 指標(biāo)要全面客觀;2) 能發(fā)現(xiàn)慢頁(yè)面的瓶頸點(diǎn);3) 滿(mǎn)足前面兩需求前提下,盡可能不影響頁(yè)面性能。
指標(biāo)要全面客觀
首先,我們采集了 web- vitals 六個(gè)指標(biāo),效果如下:

谷歌計(jì)劃于 2024 年用 INP 替換 FID,F(xiàn)ID 體現(xiàn)第一次交互的延遲時(shí)間,INP 表示所有交互中最長(zhǎng)的延遲時(shí)間。我們認(rèn)為 FID 和 INP 都有各自使用場(chǎng)景,同時(shí)保留并不矛盾。
其次,我們對(duì) PerformanceNavigationTiming 做了加工處理,效果如下:

與下面的 W3C 示例圖不同:

原因在于:
- 實(shí)際頁(yè)面運(yùn)行過(guò)程中,各階段并不一定如上圖那樣串行運(yùn)行。存在 responseEnd 耗時(shí)大于 domLoading 的情況。
- HTTP Cache 階段并無(wú)起止時(shí)間節(jié)點(diǎn),只能表明發(fā)生在 fetchStart 和 domainLookUpStart 節(jié)點(diǎn)之間。
- ServiceWorkerInit、ServiceWorkerFetchEvent 和 Request 階段只有起始節(jié)點(diǎn),沒(méi)有終止節(jié)點(diǎn),無(wú)法統(tǒng)計(jì)階段耗時(shí)。對(duì)于 Request 階段不能以 responseStart 作為終止節(jié)點(diǎn),因?yàn)閮?nèi)容在網(wǎng)絡(luò)中是分幀傳送的,不一定可以一次傳輸整個(gè)頁(yè)面內(nèi)容。
- Processing 階段以 domInteractive 為起點(diǎn),不符合客觀規(guī)律,頁(yè)面執(zhí)行到 domInteractive 時(shí)候 DOM is ready,所以 Processing 階段無(wú)法代表頁(yè)面處理過(guò)程。
所以我們結(jié)合 W3C 示例圖,以點(diǎn)、段和線的方式,展示真實(shí)的頁(yè)面運(yùn)行過(guò)程:
- 點(diǎn):指不存在終止節(jié)點(diǎn)的節(jié)點(diǎn),含:workStart、fetchStart、requestStart、domInteractive 和 domComplete,用白色圓點(diǎn)表示。
- 段:指真實(shí)存在起始和終止節(jié)點(diǎn)的處理階段,如 unload 階段值為:unloadEnd - unloadStart。同理于 redirect、DNS、TCP、SSL、Response、domContentLoadedEvent 和 loadEvent,用藍(lán)色柱狀圖表示。
- 線:含頁(yè)面加載過(guò)程中觸發(fā)的事件,如 DCL ( DomContentLoaded ) 、window.load。另外我們自定義 PageLoad 事件,表示整個(gè)頁(yè)面加載耗時(shí),值為:loadEventEnd-loadEventStart。用黃色柱狀圖表示。
段和線具體算法:
- UnloadEvent = unloadEventEnd - unloadEventStart
- Redirect = redirectEnd - redirectStart
- DNS = domainLookupEnd - domainLookupStart
- TCP = connectEnd - connectStart
- SSL = connectEnd - secureConnectionStart
- Response = responseEnd - responseStart
- loadEvent = loadEventEnd - loadEventStart
- DCL = domContentLoadedEventStart - startTime
- WindowLoad = loadEventStart - startTime
- PageLoad = loadEventEnd - startTime
此外,為了更全面體現(xiàn)頁(yè)面性能,還采集和統(tǒng)計(jì)了如下輸入:
- 小概率 (1%) 的采集完整 PerformanceEntry 數(shù)據(jù)。PerformanceEntry 包含 LargestContentfulPaint、LayoutShift、PerformanceEventTiming、PerformanceLongTaskTiming、PerformanceNavigationTiming、PerformancePaintTiming、PerformanceResourceTiming、PerformanceServerTiming 等方面數(shù)據(jù),既包含頁(yè)面本身性能指標(biāo),還涵蓋資源、網(wǎng)絡(luò)、緩存、JS 長(zhǎng)阻塞任務(wù)、慢執(zhí)行事件等多方面信息,對(duì)評(píng)估頁(yè)面性能,判斷慢頁(yè)面瓶頸點(diǎn)很有幫助??紤]到大部分頁(yè)面內(nèi)容較多,導(dǎo)致 PerformanceEntry 集合條數(shù)太大,要是 100%采集上報(bào),對(duì)帶寬、存儲(chǔ)、查詢(xún)性能都有較大影響,所以只能小概率采集。
- 頁(yè)面導(dǎo)航類(lèi)型,取值于 PerformanceNavigationTiming.type,判斷頁(yè)面是首次加載還是刷新重載等。
- 按資源類(lèi)型,統(tǒng)計(jì)各類(lèi)資源個(gè)數(shù)、總傳輸體積和總耗時(shí)。
- 按域名,統(tǒng)計(jì)各域名資源個(gè)數(shù)、總傳輸體積和總耗時(shí)。

能發(fā)現(xiàn)慢頁(yè)面瓶頸點(diǎn)
我們參考Lighthouse 50 分線 和 HTTP Archive 站點(diǎn)統(tǒng)計(jì)數(shù)據(jù),根據(jù)應(yīng)用類(lèi)型是 PC 或 M 來(lái)制定慢頁(yè)面標(biāo)準(zhǔn),具體閾值如下:

針對(duì)慢頁(yè)面,我們除了采集上節(jié)提到的 PerformanceNavigationTiming、web- vitals、小概率的完整 PerformanceEntry 數(shù)據(jù)和統(tǒng)計(jì)數(shù)據(jù)外,我們還會(huì)采集:
- TOP N 慢資源,做法:取 duration 值最大的 N 個(gè) PerformanceResourceTiming 類(lèi)型的 PerformanceEntry。
- 長(zhǎng)任務(wù),指占用 UI 線程大于 50 毫秒的任務(wù)。做法:采集所有 PerformanceLongTaskTiming 類(lèi)型的 PerformanceEntry。不過(guò)當(dāng)前大部分瀏覽器無(wú)法提供長(zhǎng)任務(wù)所在的腳本地址( containerSrc )和方法名稱(chēng)( containerName ),采集這部分?jǐn)?shù)據(jù),只能判斷長(zhǎng)任務(wù)是否發(fā)生?發(fā)生的次數(shù)。PerformanceLongTaskTiming 內(nèi)容如下:

- 慢事件,指處理時(shí)間超過(guò) 104ms 的交互事件,做法:采集所有 PerformanceEventTiming 類(lèi)型的 PerformanceEntry。
- 頁(yè)面跳轉(zhuǎn)次數(shù),值為:PerformanceNavigationTiming.redirectCount,可以輔助分析 Redirect 階段耗時(shí)多的原因。
- CLS 和 LCP 值大于慢頁(yè)面閾值時(shí),記錄其關(guān)聯(lián)的元素。
不影響頁(yè)面性能
RUM 必須通過(guò)入侵頁(yè)面,在頁(yè)面引入 JS SDK 來(lái)實(shí)現(xiàn),不可避免地影響頁(yè)面性能。作為一個(gè)發(fā)現(xiàn)和分析頁(yè)面性能的工具,不應(yīng)該加重頁(yè)面性能問(wèn)題。為了將性能影響降到最低,我們做了兩方面工作:
異步加載 JS SDK:頁(yè)面只引入功能單一、體積小的 JS 頭文件,待頁(yè)面到達(dá) DomContentLoaded 事件后,以動(dòng)態(tài) script 方式異步加載功能完整的 JS 主文件。
減少帶寬占用:
- 抽樣上報(bào):慢頁(yè)面必須上報(bào),非慢頁(yè)面抽樣上報(bào),默認(rèn)抽煙比例為 30%,減少上報(bào)次數(shù)。
- 減少上報(bào)數(shù)據(jù)體積:全量的 PerformanceEntry 數(shù)據(jù)可以完整體現(xiàn)頁(yè)面性能,不少頁(yè)面動(dòng)輒超過(guò)白條 PerformanceEntry 數(shù)據(jù),體積過(guò)大,所以只能小概率采集全量 PerformanceEntry 數(shù)據(jù),計(jì)算和采集 PerformanceEntry 的統(tǒng)計(jì)數(shù)據(jù)。
綜上所述我們采集指標(biāo)主要兩大類(lèi):PerformanceEntry 和 web-vitals。
SPA 應(yīng)用非首頁(yè)性能該如何評(píng)估?
采集上述指標(biāo),已經(jīng)可以較為客觀全面評(píng)估常規(guī)頁(yè)面和 SPA 應(yīng)用首頁(yè)的頁(yè)面性能。但是 SPA 應(yīng)用非首頁(yè)不是瀏覽器標(biāo)準(zhǔn),在 SPA 路由切換過(guò)程中:
- 瀏覽器僅會(huì)執(zhí)行 History.replaceState()方法,不會(huì)也不該重新生成 PerformanceNavigationTiming 數(shù)據(jù)。
- 多數(shù) PerformanceEntry 數(shù)據(jù)包含 SPA 首頁(yè)以來(lái)所有路由切換頁(yè)面的性能指標(biāo)。以 PerformanceResourceTiming 為例,無(wú)法通過(guò) History.replaceState()方法拿到真實(shí)路由切換的時(shí)機(jī),排除 PerformanceResourceTiming 集合中的歷史數(shù)據(jù),從而獲取當(dāng)前路由的 PerformanceResourceTiming 數(shù)據(jù)。因?yàn)楦髑岸丝蚣茉?SPA 路由切換過(guò)程中,大多數(shù)會(huì)先執(zhí)行其框架內(nèi)部邏輯,而后再觸發(fā) History.replaceState()方法,所以 History.replaceState()方法觸發(fā)時(shí)間晚于路由切換的執(zhí)行時(shí)間。
- web-vitals 暫時(shí)也不支持采集 SPA 非首頁(yè)路由切換后的性能指標(biāo)。
所以,對(duì)于上述指標(biāo) SPA 非首頁(yè)無(wú)法或無(wú)法準(zhǔn)確拿到,所以我們暫不評(píng)估 SPA 非首頁(yè)性能。
針對(duì)業(yè)內(nèi) SPA 非首頁(yè)性能難評(píng)估的情況,字節(jié) WebPro 創(chuàng)造性地推出 SPA_LOAD 的概念,基本邏輯為:以觸發(fā) history.replaceState() 方法為起點(diǎn),通過(guò) MutationObserver 監(jiān)聽(tīng) dom 變更、資源加載、請(qǐng)求發(fā)送等變更事件來(lái)尋找一個(gè)頁(yè)面達(dá)到穩(wěn)定態(tài)的時(shí)間為終點(diǎn),通過(guò)計(jì)算起終點(diǎn)之間的耗時(shí),來(lái)衡量 SPA 非首頁(yè)的頁(yè)面性能。SPA_LOAD 類(lèi)似于常規(guī)頁(yè)面 onload 事件,但是起始時(shí)間比真實(shí)路由切換時(shí)間晚,到終止時(shí)間時(shí)頁(yè)面可能已經(jīng)加載完畢,略有不足,不過(guò)已是當(dāng)前最佳的方案,后面我們可能引入。
采集指標(biāo)時(shí)機(jī)
只有采集真實(shí)、準(zhǔn)確的指標(biāo)值,才能真實(shí)反映頁(yè)面性能,反之,可能誤導(dǎo)產(chǎn)研同學(xué),錯(cuò)誤評(píng)估真實(shí)的頁(yè)面性能。所以選擇采集指標(biāo)時(shí)機(jī)有幾大原則:
- 指標(biāo)準(zhǔn),最關(guān)鍵是要保證指標(biāo)是準(zhǔn)的,不準(zhǔn)不如不采。
- 樣本多,上報(bào)可靠,部分指標(biāo),如 CLS、INP、PerformanceEventTiming 等,越晚采集值越準(zhǔn),但是越晚采集,留給上報(bào)的時(shí)間越少,數(shù)據(jù)上報(bào)失敗的概率越大,為了盡量多采集數(shù)據(jù)樣本,我們不能等到頁(yè)面關(guān)閉時(shí)再采集指標(biāo)、提交上報(bào)。
- 公平,部分指標(biāo),如 CLS、INP、LCP 等,隨著頁(yè)面打開(kāi)時(shí)間邊長(zhǎng),值可能也跟著變大。對(duì)于這類(lèi)指標(biāo),我們只能保證數(shù)據(jù)”樣本多“的前提下,選擇一個(gè)相對(duì)合理、對(duì)“所有項(xiàng)目”都公平的采集時(shí)機(jī)。
- 一次上報(bào),web-vitals 中部分指標(biāo)如:LCP、CLS、INP,每次變更都會(huì)觸發(fā)其回調(diào)函數(shù),谷歌官方建議每次指標(biāo)值變更都采集上報(bào)。這種處理邏輯,指標(biāo)值是更準(zhǔn),但是占用太多前端的連接、帶寬和 CPU 資源,也嚴(yán)重加大后端接收程序的處理難度,不是各合理均衡的選擇。所以我們要找到一個(gè)合適的采集時(shí)機(jī),一次采集并上報(bào)所有的性能指標(biāo)。
那么如何確定采集時(shí)機(jī)?我們得先分析 PerformanceEntry 和 web-vitals 兩類(lèi)指標(biāo)數(shù)據(jù)得準(zhǔn)確生成時(shí)間:
對(duì)于 PerformanceEntry 數(shù)據(jù),onload 事件觸發(fā)時(shí),頁(yè)面已接近加載完畢,PerformanceEntry 中影響首屏加載的絕大部分指標(biāo)數(shù)據(jù)已經(jīng)生成。未生成的數(shù)據(jù)對(duì)評(píng)估頁(yè)面性能影響不大,如:PerformanceNavigationTiming 中的 loadEventEnd 指標(biāo)值。所以我們認(rèn)為 onload 事件觸發(fā)件時(shí),可以采集 PerformanceEntry 指標(biāo)。
web-vitals 中各指標(biāo)生成原理不一,onload 事件觸發(fā)時(shí):
- TTFB、FCP 指標(biāo)已生成且不會(huì)變,可以采集。
- LCP 對(duì)應(yīng)的最大元素大概率已加載完畢,所以我們認(rèn)為這時(shí)候 LCP 值大概率是準(zhǔn)的,可以采集。
- CLS 值無(wú)法確定是否準(zhǔn)確,其計(jì)算邏輯為:頁(yè)面打開(kāi)后每 5s 作為一個(gè) session 窗口,累加該窗口內(nèi)產(chǎn)生的偏移值即是 CLS 值,如果下一個(gè) session 窗口的 CLS 值大于上一個(gè) session 窗口,則替換。所以對(duì)于 CLS 指標(biāo)來(lái)說(shuō),打開(kāi)頁(yè)面 5S 后、最好 5S 或其整數(shù)倍時(shí)采集,比較合適,對(duì)”所有項(xiàng)目“也比較公平。
- FID、INP 也無(wú)法確定是否準(zhǔn)確,它們依賴(lài)用戶(hù)交互操作后才生成,交互操作含:點(diǎn)擊、輸入、拖放、觸摸等事件。FID 是第一次交互的延遲時(shí)間,INP 取多次交互操作中延遲時(shí)間最大的值。這兩指標(biāo)都依賴(lài)于用戶(hù)操作,INP 可能會(huì)隨著用戶(hù)操作次數(shù)變多而值變大,所以任何時(shí)間都沒(méi)法保證準(zhǔn)確拿到這兩指標(biāo)值。
基于上述考慮,我們認(rèn)為至少要滿(mǎn)足:觸發(fā) onload 事件或打開(kāi)頁(yè)面 5s 之一條件時(shí),才能保證 PerformanceEntry 或部分 web-vitals 指標(biāo)值準(zhǔn)確,采集才有意義。在追求”樣本多“的原則下,結(jié)合 RUM SDK 是 onload 事件后異步加載的實(shí)際情況,我們針對(duì)頁(yè)面是否被正常關(guān)閉前提下,總共設(shè)置了三種采集時(shí)機(jī),其特點(diǎn)如下:

為了避免采集指標(biāo)影響頁(yè)面性能,我們異步加載 RUM JS SDK,web-vitals 中各指標(biāo)默認(rèn)僅支持異步回調(diào),異步加載再異步回調(diào),導(dǎo)致采集時(shí)機(jī)時(shí)仍可能無(wú)法拿到各指標(biāo)值,所以我們對(duì) web-vitals 源碼做了改造,支持同步獲取各指標(biāo)值。
上報(bào)方式
采集到指標(biāo)后,需要選擇恰當(dāng)上報(bào)方式,將指標(biāo)可靠的發(fā)送到后端。上報(bào)方式包含兩個(gè)部分:上報(bào)機(jī)制和上報(bào)時(shí)機(jī)。
選擇合適的上報(bào)機(jī)制,首先,要滿(mǎn)足功能需求,瀏覽器兼容度高,對(duì)數(shù)據(jù)大小最好沒(méi)限制;其次,能感知上報(bào)請(qǐng)求異常,便于上報(bào)重試,進(jìn)而提高上報(bào)可靠性;最后,客戶(hù)端支持設(shè)置超時(shí)時(shí)間,避免長(zhǎng)時(shí)間占用忘了連接,加大后端服務(wù)壓力。常見(jiàn)上報(bào)機(jī)制有四種,分別是:Image、XMLHttpRequest、sendBeacon、Fetch API。其特點(diǎn)如下:
Image | XMLHttpRequest | sendBeacon | Fetch | |
基本原理 | 創(chuàng)建一個(gè) 1 像素、隱藏的 img DOM,將上報(bào)地址和上報(bào)內(nèi)容包含在 img 的 src 中。上報(bào)成功則返回 200 狀態(tài)碼 | 利用瀏覽器內(nèi)置對(duì)象 XMLHttpRequest 上報(bào)數(shù)據(jù) | 使用專(zhuān)門(mén)設(shè)計(jì)用于發(fā)送分析數(shù)據(jù)的 navigator.sendBeacon()方法,以異步發(fā)送 HTTP POST 請(qǐng)求的方式將分析數(shù)據(jù)提交到后端 | fetch 是一個(gè)現(xiàn)代的、基于 Promise 的用于發(fā)送 HTTP 請(qǐng)求的 API |
瀏覽器兼容性 | 高 | 高 | 中,不支持 IE | 中偏低,不支持 IE |
數(shù)據(jù)大小限制 | 小于 8K 各瀏覽器大小限制不一,且受制于 CDN、后端代理和 web 服務(wù)器,默認(rèn)值常為 8K。8K 指用 URI 編碼后的長(zhǎng)度 | 用 POST 請(qǐng)求,無(wú)限制 | 有,部分瀏覽器小于 64K | 用 POST 請(qǐng)求,無(wú)限制 |
感知上報(bào)異常 | 部分支持。 請(qǐng)求返回狀態(tài)碼為 404 或 204 時(shí)會(huì)觸發(fā) img onerror 事件。狀態(tài)碼大于等于 400,不會(huì)觸發(fā) onerror 事件,如 400、500、502 和 504 等。 | 支持 | 不支持。 sendBeacon()返回值,只能表示瀏覽器是否發(fā)出請(qǐng)求 | 支持 |
可設(shè)置超時(shí) | 不可以,依賴(lài)服務(wù)端的設(shè)置 | 可以 | 不可以 | 可以 |
優(yōu)點(diǎn) | 使用簡(jiǎn)單、兼容度高 | 功能強(qiáng)大,靈活易擴(kuò)展 無(wú)大小限制,兼容度高 | 使用簡(jiǎn)單,可靠性高 頁(yè)面關(guān)閉時(shí),仍可發(fā)送 | 相比于 XMLHttpRequest,使用更簡(jiǎn)介、功能更強(qiáng)大 |
缺點(diǎn) | 數(shù)據(jù)大小有限制,難感知上報(bào)異常 | 代碼編寫(xiě)略復(fù)雜 跨域處理要留意 | 無(wú)法感知上報(bào)異常,函數(shù)返回值 true、false 只能代表是否發(fā)送成功 | 同 XMLHttpRequest 瀏覽器兼容度最低 |
適用場(chǎng)景 | 上報(bào)數(shù)據(jù)小,可靠性要求不高 | 功能需求多 建議以 POST 方式用 text/plain 或 application/x-www-form-urlencoded 格式上報(bào),CORS 預(yù)驗(yàn)證 | 需要在頁(yè)面關(guān)閉時(shí),上報(bào)數(shù)據(jù) | 同 XMLHttpRequest,更適用于瀏覽器分布較新的終端 |
上述結(jié)論:依賴(lài)于 chrome114
相比于 Fetch,XMLHttpRequest 功能幾乎一致,兼容性更高;與 Image 對(duì)比,XMLHttpRequest 具有兼容度高、數(shù)據(jù)大小沒(méi)限制、能感知異常和可設(shè)置超時(shí)時(shí)間等優(yōu)勢(shì);XMLHttpRequest 是頁(yè)面正常(未關(guān)閉)情況下,發(fā)送指標(biāo)數(shù)據(jù)的首選上報(bào)機(jī)制。至于 sendBeacon,雖然存在諸多不足,但是頁(yè)面關(guān)閉時(shí)仍可以上報(bào)數(shù)據(jù),成功率還較高,適合作為在頁(yè)面關(guān)閉時(shí),發(fā)送尚未發(fā)送的指標(biāo)數(shù)據(jù)的上報(bào)機(jī)制。
既然選擇了 sendBeacon 作為頁(yè)面關(guān)閉時(shí)發(fā)送指標(biāo)數(shù)據(jù)的上報(bào)機(jī)制,那該如何判斷頁(yè)面被關(guān)閉?傳統(tǒng)方案是監(jiān)聽(tīng) unload 或 beforeunload 事件,該方案存在兩個(gè)不足:
- 不能滿(mǎn)足功能需求。手機(jī)端用戶(hù)離開(kāi)頁(yè)面時(shí),更習(xí)慣將瀏覽器隱藏,而不是關(guān)閉瀏覽器。隱藏頁(yè)面時(shí),不會(huì)觸發(fā) unload 和 beforeunload 事件。
- 性能有損耗。部分瀏覽器,監(jiān)聽(tīng)到 unload 或 beforeunload 事件后,無(wú)法使用 bfcache,導(dǎo)致頁(yè)面性能降低。
更合適、更現(xiàn)代的方案是監(jiān)聽(tīng) pagehide 或 visibilitychange===hiden 事件,該方案除了避免傳統(tǒng)方案存在的兩不足,兼容度也會(huì)更高。對(duì)于 SPA 項(xiàng)目我們不采集非首頁(yè)性能指標(biāo),觸發(fā)History.replaceState()方法也算離開(kāi)頁(yè)面。
綜上所述,整體上報(bào)機(jī)制為:1)頁(yè)面正常(未關(guān)閉),到采集時(shí)機(jī)時(shí),SDK 采集性能指標(biāo)數(shù)據(jù),使用 XMLHttpRequest 機(jī)制上報(bào);2)通過(guò)監(jiān)聽(tīng) pagehide 或 visibilitychange===hiden 事件,當(dāng)頁(yè)面被關(guān)閉時(shí),如果滿(mǎn)足任一采集時(shí)機(jī)條件,則立即采集指標(biāo),使用 sendBeacon 機(jī)制上報(bào)。
整體方案
綜上所述,我們整理 RUM 實(shí)施大綱如下:

實(shí)際編碼過(guò)程中,具體處理流程如下:

優(yōu)缺點(diǎn)
在實(shí)施過(guò)程中,我們總結(jié) RUM 優(yōu)缺點(diǎn)如下:

RUM 架構(gòu)設(shè)計(jì)復(fù)雜,實(shí)施成本較高,由于是技術(shù)剛需,只能投入資源,努力做好。
針對(duì) 無(wú)診斷結(jié)果和優(yōu)化建議 的缺點(diǎn),可以結(jié)合 SYN,取長(zhǎng)補(bǔ)短,利用 SYN 診斷慢頁(yè)面性能瓶頸點(diǎn)分布。
對(duì)于 無(wú)評(píng)分,沒(méi)法判斷頁(yè)面性能優(yōu)劣 的問(wèn)題,我們分三步走:首先,制定慢頁(yè)面標(biāo)準(zhǔn),判斷單次頁(yè)面是否快慢,標(biāo)準(zhǔn)值前文已有描述;其次,統(tǒng)計(jì)該頁(yè)面各重要指標(biāo)的 AVG、TP50、TP90、TP99 值,全面評(píng)估頁(yè)面所有請(qǐng)求的性能分布;最后,我們會(huì)對(duì)頁(yè)面所在的應(yīng)用進(jìn)行評(píng)分,直接告訴研發(fā)同學(xué),該應(yīng)用性能優(yōu)劣,應(yīng)用評(píng)分具體做法,會(huì)在下面《建立評(píng)分體系》章節(jié)細(xì)講。
三、整體架構(gòu)設(shè)計(jì)
前文深入分析了 SYN 和 RUM 各自特點(diǎn)、使用方法及優(yōu)缺點(diǎn)等,我們發(fā)現(xiàn) SYN 和 RUM 各有所長(zhǎng)、無(wú)法替代,最好同時(shí)引用 SYN 和 RUM,構(gòu)建體系化性能監(jiān)控架構(gòu),提供性能監(jiān)控和性能分析工具鏈,支持產(chǎn)研同學(xué)在 devpos 各階段中發(fā)現(xiàn)和定位頁(yè)面性能問(wèn)題。

在編碼、構(gòu)建和測(cè)試階段,研發(fā)同學(xué)可以利用 SYN 來(lái)做頁(yè)面性能測(cè)試,判斷頁(yè)面性能是否達(dá)標(biāo)?如果頁(yè)面性能有問(wèn)題,再利用 SYN 診斷性能問(wèn)題,獲得優(yōu)化建議。此舉解決前端頁(yè)面長(zhǎng)期以來(lái),前端頁(yè)面做性能測(cè)試難、交付頁(yè)面質(zhì)量無(wú)標(biāo)準(zhǔn)等痛點(diǎn)。應(yīng)用部署后,再利用 RUM 采集真實(shí)用戶(hù)頁(yè)面性能,評(píng)估真實(shí)頁(yè)面性能,如果還存在慢頁(yè)面,仍可以使用 SYN 定位慢頁(yè)面性能瓶頸點(diǎn),并利用診斷結(jié)果和優(yōu)化建議,提高優(yōu)化效率。除此之外,SYN 還可以用來(lái)做競(jìng)品對(duì)比,達(dá)到知己知彼、快競(jìng)爭(zhēng)對(duì)手一步的目的。

有了 SYN 和 RUM,我們可以構(gòu)建在線持續(xù)優(yōu)化慢頁(yè)面的閉環(huán),如上圖。RUM 負(fù)責(zé)采集真實(shí)用戶(hù)產(chǎn)生的慢頁(yè)面,經(jīng)后臺(tái)存儲(chǔ)、聚合,自動(dòng)將 TOPN 的慢頁(yè)面創(chuàng)建 SYN JOB,待 JOB 運(yùn)行完畢,將診斷結(jié)果和優(yōu)化建議以告警防止通知研發(fā)同學(xué),研發(fā)同學(xué)利用 SYN 優(yōu)化建議,再利用 devtools、webpack 等工具,改進(jìn)頁(yè)面,交付高質(zhì)量頁(yè)面,降低慢頁(yè)面的頻次。如此循環(huán)迭代,持續(xù)優(yōu)化應(yīng)用頁(yè)面性能,最終應(yīng)用能達(dá)到極致性能。
三、建立評(píng)判體系
引入 SYN,自研 RUM SDK,采集到眾多 SYN 和 RUM 指標(biāo)數(shù)據(jù)后,我們將著手建立評(píng)判體系,評(píng)估各應(yīng)用、團(tuán)隊(duì)、部門(mén),乃至整個(gè)公司的性能情況,輸出少數(shù)幾個(gè)關(guān)鍵指標(biāo)和評(píng)分,直觀告訴各層級(jí)、各角色員工其所在組織及同級(jí)組織的頁(yè)面性能情況,通過(guò)得分和同級(jí)對(duì)比,評(píng)判是否要優(yōu)化頁(yè)面性能?
建立評(píng)判體系時(shí)我們秉持著:既要突出重點(diǎn)、關(guān)鍵指標(biāo),同時(shí)還能全面、綜合、客觀真實(shí)地反映頁(yè)面性能 的原則。所以我們將評(píng)判體系分為兩大塊,其一,展示最關(guān)鍵的性能指標(biāo)。其二,輸出各指標(biāo)、應(yīng)用、團(tuán)隊(duì)、部門(mén)及公司層級(jí)的性能評(píng)分和層級(jí)。
展示最關(guān)鍵的性能指標(biāo)
我們從 web-vitals 和 performanceNavigationTiming 中各選一個(gè)最能代表頁(yè)面性能的指標(biāo),分別為:DCL 和 LCP。LCP 兼容度不高且可能被偽造,DCL 既能代替 LCP 部分反映首屏性能且兼容度高、難以偽造,和 LCP 相輔相成,最能體現(xiàn)頁(yè)面性能。

TP90 代表 90%用戶(hù)的體驗(yàn)下限,與 AVG、TP50、TP75 比,覆蓋和統(tǒng)計(jì)更廣的用戶(hù),還能屏蔽頁(yè)面在手機(jī)端特殊網(wǎng)絡(luò)環(huán)境下,產(chǎn)生的少數(shù)臟數(shù)據(jù),更具有代表性。
輸出各級(jí)評(píng)分
應(yīng)用性能評(píng)分
為了全面、綜合和客觀的評(píng)估應(yīng)用頁(yè)面性能。我們將選擇各維度具有代表性指標(biāo),參考 HTTP Archive 給予的業(yè)內(nèi)指標(biāo)分布,根據(jù)應(yīng)用特性,如應(yīng)用類(lèi)型( PC 或 M 端 )、終端用戶(hù)( C 端用戶(hù)、B 端客戶(hù)和內(nèi)部員工),設(shè)立不同的評(píng)分基線,算出各指標(biāo)得分。再根據(jù)各指標(biāo)重要程度設(shè)置權(quán)重,通過(guò)加權(quán)平均算法,求得應(yīng)用性能評(píng)分。流程如下:

獲取應(yīng)用性能分過(guò)程中涉及幾個(gè)重要流程:1) 指標(biāo)篩選及權(quán)重設(shè)置;2) 選擇評(píng)分算法;3) 確立指標(biāo)基線;4) 使用加權(quán)平均算法計(jì)算應(yīng)用性能分。下面逐一介紹。
指標(biāo)篩選及權(quán)重設(shè)立
此過(guò)程中,我主要考慮兩點(diǎn):
全面綜合考慮。頁(yè)面性能涵蓋多方面,傳統(tǒng)上只用首字節(jié)、白屏、首屏?xí)r間等少數(shù)指標(biāo)來(lái)衡量,較為片面,不夠客觀。我們認(rèn)為評(píng)判頁(yè)面性能應(yīng)該涵蓋各維度指標(biāo),如:頁(yè)面加載、交互體驗(yàn)和視覺(jué)體驗(yàn)。此外我們還引入慢 API 比例的概念,API 請(qǐng)求比例指頁(yè)面打開(kāi)后 API 耗時(shí)超過(guò) 3s 的請(qǐng)求比例,慢 API,即可能影響首屏加載耗時(shí),也會(huì)影響交互過(guò)程中的用戶(hù)體驗(yàn)。為了讓研發(fā)同學(xué)關(guān)注慢頁(yè)面、將在線 SYN 作為日常開(kāi)發(fā)性能評(píng)估工具,我們將 SYN 評(píng)分也作為權(quán)重指標(biāo),后臺(tái)系統(tǒng)每天會(huì)統(tǒng)計(jì)訪問(wèn)次數(shù) TOP10 的慢頁(yè)面并自動(dòng)創(chuàng)建 SYN 定時(shí)任務(wù),待任務(wù)執(zhí)行、分析完畢后,將優(yōu)化建議和診斷結(jié)果通知研發(fā)同學(xué)。SYN 評(píng)分項(xiàng),包含性能分和最佳實(shí)踐分,兩者都是百分制。
突出重點(diǎn)。提高重要指標(biāo)的權(quán)重比。如:加載指標(biāo)用于衡量頁(yè)面能不能用,最為關(guān)鍵,所以賦予權(quán)重占比最大。LCP 是最重要的加載指標(biāo),權(quán)重占比也相應(yīng)提高。由于 LCP 本身不一定完全合理且可能被偽造,所以評(píng)判頁(yè)面加載性能時(shí),還引入 DCL、FCP、TTFB、WindwLoad 和 PageLoad 等加載指標(biāo)。該做法,優(yōu)點(diǎn):指標(biāo)多,維度廣、角度大、更全面和更客觀準(zhǔn)確;缺點(diǎn):增加評(píng)判系統(tǒng)復(fù)雜度和難度。
基于上述兩點(diǎn)考慮,我們指標(biāo)篩選結(jié)果和權(quán)重占比設(shè)置,如下圖:

各指標(biāo)以其 TP90 統(tǒng)計(jì)值,參與評(píng)分運(yùn)算。
選擇評(píng)分算法
評(píng)分算法主要參考 Lighthouse 評(píng)分曲線模型,基本原理是:設(shè)置兩個(gè)控制點(diǎn),通常是 TP50 和 TP90,即得 50 或 90 分時(shí)的指標(biāo)值點(diǎn),然后根據(jù)這兩個(gè)控制點(diǎn),生成對(duì)數(shù)正態(tài)曲線,通過(guò)該曲線可以獲得任一指標(biāo)值對(duì)應(yīng)的得分。下圖是 M 端 LCP 的評(píng)分曲線:

m 表示中位數(shù),圖中 m 值為 4000ms,表示當(dāng) LCP 值為 4000ms 時(shí),得 50 分;同理 p10 為 2520ms,LCP 值為 2529ms 時(shí),得 90 分。設(shè)置 m 和 p10 后,會(huì)生成右邊的評(píng)分曲線模型,根據(jù)該模型可以獲得 LCP 值從 0 到正無(wú)窮時(shí)的得分。
確立指標(biāo)基線
確立指標(biāo)基線是為了給評(píng)分算法提供兩個(gè)控制點(diǎn),即 m 和 p10 的值。確立方法有三種:
- 直接借用 Lighthouse 配置。以 Lighthouse 對(duì)應(yīng)指標(biāo)的 50 分和 90 分閾值為 m 和 p10 控制點(diǎn)值,如 web-vitals 中各指標(biāo)。
- 參考 HTTP Archive 統(tǒng)計(jì)數(shù)據(jù),以統(tǒng)計(jì)數(shù)據(jù)中的 p10、p75 值為 m 和 p10 控制點(diǎn)值。如 performanceNavigationTiming 各指標(biāo)。
- 自建基線。少數(shù)指標(biāo)基線無(wú)法從上述兩種方法確立,只能自建基線。具體做法:以當(dāng)前后臺(tái)系統(tǒng)拿到的數(shù)據(jù)為樣本,以樣本的 tp75 和 tp95 值為 m 和 p10 控制點(diǎn)值。適用于慢 api 比例指標(biāo)。
確立基線過(guò)程中,應(yīng)考慮應(yīng)用價(jià)值和研發(fā)要求的不同,根據(jù)應(yīng)用特性,有針對(duì)性的設(shè)置。首先,PC 端和 M 端類(lèi)型的應(yīng)用,要設(shè)置不同的指標(biāo)基線,所幸 Lighthouse 和 HTTP Archive 都提供 PC 端和 M 端的配置參考;其次,根據(jù)應(yīng)用實(shí)際終端用戶(hù)類(lèi)型,有針對(duì)性的調(diào)整閾值。C 端和 B 端應(yīng)用,直接產(chǎn)生業(yè)務(wù)價(jià)值,性能要求要比內(nèi)部應(yīng)用高,兩控制點(diǎn)值應(yīng)該更低。
使用加權(quán)平均算法計(jì)算應(yīng)用性能分
根據(jù)指標(biāo) tp90 值、指標(biāo)基線和評(píng)分算法,求得該指標(biāo)的百分制得分。
使用加權(quán)平均算法求應(yīng)用性能分,結(jié)果 = (Σ (指標(biāo)tp90值 × 指標(biāo)權(quán)重)) / (Σ 權(quán)重) ,其中:Σ 表示求和。

各級(jí)組織評(píng)分
至于求各級(jí)組織,含團(tuán)隊(duì)、部門(mén)及公司的性能分,則根據(jù)其管轄的應(yīng)用個(gè)數(shù)、應(yīng)用性能分及應(yīng)用權(quán)重,仍使用加權(quán)平均算法獲取組織分。流程如下:

求組織性能分的難點(diǎn)是:如何設(shè)置應(yīng)用權(quán)重?我們主要參考應(yīng)用的 PV 區(qū)間和應(yīng)用級(jí)別。PV 層級(jí)越大、應(yīng)用級(jí)別越高,權(quán)重越大。具體配置參考如下:

PV區(qū)間中的PV 值指采用 PV,而非真實(shí) PV,采用 PV=采集到 RUM 數(shù)據(jù)量/抽樣比例。
經(jīng)過(guò)上述步驟,我們能獲得應(yīng)用性能分,以及各級(jí)組織的性能分,如團(tuán)隊(duì)性能分、部門(mén)性能分及之家性能分,展示效果如下:

性能分參考lighthouse標(biāo)準(zhǔn),50分以上算合格,90分以上才算優(yōu)秀。
四、總結(jié)
通過(guò)頁(yè)面性能監(jiān)控和評(píng)判體系建設(shè),我們既有原始頁(yè)面性能數(shù)據(jù),又有聚合統(tǒng)計(jì)值,還有最終評(píng)分。通過(guò)評(píng)分、統(tǒng)計(jì)和原始數(shù)據(jù),打通了發(fā)現(xiàn)、定位和分析性能問(wèn)題的鏈路。研發(fā)同學(xué)可以通過(guò)評(píng)分直觀判斷應(yīng)用性能優(yōu)劣是否需要優(yōu)化?如果需要優(yōu)化,再通過(guò)聚合統(tǒng)計(jì)數(shù)據(jù),分析應(yīng)用瓶頸點(diǎn);定位具體瓶頸點(diǎn)時(shí),可以查看明細(xì)數(shù)據(jù),輔助分析產(chǎn)生瓶頸點(diǎn)的具體原因;改進(jìn)后可以通過(guò)通過(guò)統(tǒng)計(jì)查看優(yōu)化效果,最終反映到提高評(píng)分上。
受限于篇幅,本文僅能介紹頁(yè)面性能監(jiān)控和評(píng)判體系建設(shè)相關(guān)的實(shí)踐。一個(gè)完整的頁(yè)面性能監(jiān)控系統(tǒng),還應(yīng)該包含:監(jiān)控、報(bào)警、優(yōu)化、治理等模塊,不僅僅只是指標(biāo),能度量頁(yè)面性能,發(fā)現(xiàn)其中性能瓶頸點(diǎn),幫助研發(fā)同學(xué)提升優(yōu)化效率,還要治本,通過(guò)構(gòu)建一系列前端工具鏈,改進(jìn)交付過(guò)程,通過(guò)規(guī)范、工具和流程,從源頭上提高頁(yè)面交付質(zhì)量,避免將問(wèn)題帶到線上,先于用戶(hù)發(fā)現(xiàn)性能問(wèn)題。
五、參考文獻(xiàn)
Web Vital Metrics for Single Page Applications
一個(gè)收集和分析網(wǎng)站性能數(shù)據(jù)的項(xiàng)目,旨在幫助 Web 開(kāi)發(fā)者了解互聯(lián)網(wǎng)的技術(shù)趨勢(shì)以及性能優(yōu)化的最佳實(shí)踐。

































