汽車之家頁面性能監控建設實踐
一、前言
關注用戶體驗,提高頁面性能,是每位前端研發同學的日常工作之一。提高頁面性能對業務的幫助,雖不易衡量,但肯定是利遠大于弊。如何衡量頁面性能優劣?如何幫助研發同學快速定位到頁面性能瓶頸點?一直是前端的重點工作之一。本文分享汽車之家在頁面性能監控建設方面的部分工作,主要包含三方面:
技術選型
- 該選擇哪些頁面性能監控技術方案?
- 在盡可能不影響頁面性能的前提下,既能客觀、全面衡量頁面性能,又能幫助研發同學快速定位性能瓶頸點,該采集哪些指標?
- SPA 應用非首頁性能該如何評估?
- 在盡可能不影響頁面性能和保證采集數據精準性的前提下,盡量多地采集和上報數據,如何選擇合適的指標采集時機和上報方式?
整體架構設計
整合選中技術方案,構建體系化性能監控架構,提供性能監控和性能分析工具鏈,支持產研同學在 DevOps 各階段中發現和定位頁面性能問題。
建立評判體系
有數據,我們才能度量;有評分,技術才好改進。
利用采集到的眾多指標,根據應用特性,按各性能指標的重要程度,設置不同的基線和權重,以加權平均的方式,求得應用得分。通過分數,直觀告訴研發同學應用頁面快或慢?應用性能高或低?是否需要改進?
應用得分只能反映單個應用的性能情況,主要服務于產研同學。一家公司有多個部門,每個部門有多個團隊,一個團隊有多個應用,我們需要公司、部門和團隊層級的性能得分,才能讓各級領導直觀了解其負責隊伍的頁面性能,也方便上級領導判斷下級各隊伍之間的性能高低,所以我們根據應用 PV 數和應用級別,仍以加權平均算法,獲得團隊、部門和公司性能得分。
二、技術選型
根據監控頁面性能時的運行環境,我們將技術方案分為兩種:合成監控(Synthetic Monitoring,SYN)和真實用戶監控(Real User Monitoring,RUM)。
合成監控 (以下簡稱 SYN)
指在通過仿真環境運行頁面,評估頁面性能。早期代表工具有我們熟知的 YSlow 和 PageSpeed。隨著技術進步,當前三個最成熟的 SYN 工具為:Lighthouse、WebPageTest 和 SiteSpeed。Lighthouse 雖然僅支持 Chrome 瀏覽器、實施成本較高,但是有谷歌支持、易擴展、指標豐富、有評分諸多優勢,已逐步代替 WebPageTest,成為 SYN 首選工具。 如下以 Lighthouse 為例介紹 SYN 的運行過程、優缺點。
運行過程
從運行結果頁面來看,Lighthouse 除了輸出關鍵性能指標值和評分外,還向我們提供優化建議和診斷結果。10.1.0 版 Lighthouse 分別內置 94、16 條性能和最佳實踐方面的規范或建議,其中不乏日常研發比少留意且較有意義的規范,如:最大限度地減少主線程工作(mainthread-work-breakdown)、網頁已阻止恢復往返緩存(bf-cache)、減少 js 文件中未使用的 JavaScript (unused-javascript)等。
推薦使用 Node Cli 或 Node Module 方式運行 Lighthouse,同時輸出 html 和 json 格式的結果。json 中數據更全面,包含如:最大內容渲染時間元素(largest-contentful-paint-element)、應避免出現長時間運行的主線程任務(long-tasks)等明細信息。
優缺點
根據我們實踐,總結 Lighthouse 有如下優缺點:
改進
針對上述不足和產品需求,我們做了一些改進:
n 為解決 默認無基準環境,相同頁面在不同用戶端運行,因運行環 境和硬件資源不同,導致結果不同 的問題,我們做了兩方面的改進:
首先,提供 SYN 基準運行環境。利用 Lighthouse Node Module 自研 Web 版 SYN 服務并部署在容器中。通過在 Node 服務端添加隊列策略,保證單容器任意時間只允許運行一個 SYN 任務,且每個容器的硬件資源( 4 核 + 4G )和網速配置( M 端應用統一使用 10M 網速 )都一樣,從而保證運行結果和最終得分是相對公平和可靠的。
其次,支持以計劃任務,間隔 6、12 或 24 小時 的方式運行 SYN 任務。 統計多次運行結果指標的 AVG、TP 值,排除少數異常運行的結果偏差。
- 針對 運行慢,占用資源多 的問題。我們認為相同頁面,如果沒有改版,沒必要過于頻繁的持續測試,建議 PV 量大或重要頁面添加計劃任務 12 小時及以上時間間隔運行一次,這樣既能客觀反映頁面性能情況,也能節省資源。
- 將 SYN 集成到 CI 流水線中,將 SYN 作為上線前頁面性能測試或競品對比的實施工具。
適用場景
- 將 SYN 作為頁面性能測試工具,集成到前端監控后臺應用、QA 套件 和 CI 中。建議研發同學交付頁面前,通過 SYN 評估頁面性能并根據優化建議和診斷結果,改進頁面質量缺陷,提高交付質量。
- 利用 SYN 做競品對比。
- 將 SYN 作為分析 RUM 捕獲到慢頁面的首選工具,結合 Chrome DevTools , 從實踐來看可以定位到多數問題。
使用方法
總結
SYN 實施成本低,便于統一標準,相比 RUM,受運行時環境的影響更小,結果更具有可比性和可復現性,是性能監控的重要一環?;?Lighthouse,借助 K8S 等容器編排技術,快速搭建提供基準環境的 SYN Web 服務是建設頁面性能監控體系的第一階段。該階段以提供評估頁面性能、分析慢頁面等關鍵功能為主。雖然 Lighthouse 還存在 僅支持谷歌瀏覽器,代表性不足,也不能真實反映真實用戶端的性能情況 這兩個問題,但瑕不掩瑜,可以作為 SYN 的首選方案。同時,這兩個問題我們將通過添加另外一種技術方案:真實用戶監控(RUM)來解決。
真實用戶監控 ( 簡稱 RUM)
顧名思義,指監控運行在真實用戶終端(瀏覽器),采集用戶運行頁面時候真實的性能指標。業內技術方案主要分為兩種:
依托 W3C 組織且各瀏覽器廠商廣泛支持技術方案:PerformanceTiming 和 PerformanceNavigationTiming。偏向從瀏覽器處理過程角度去衡量頁面運行時各節點、各階段的耗時。
各廠根據實際需求自研技術方案。谷歌 web-vitals 是其中最優秀的代表,它從用戶體驗角度,用更通俗易懂的指標展現頁面性能。
除上述兩種常見技術方案外,少數商業前端監控服務廠商,除了支持 W3C 和 web-vitals 外,還提供少數自定義性能指標,如:阿里 ARMS 中的 FMP 、字節 WebPro 里的 SPA_LOAD 。SPA_LOAD 用于評估 SPA 非首頁的頁面性能,有較大創新性,后面還會提及。
技術選型
技術選型主要解決兩個問題:1)W3C 的 PerformanceTiming 和 PerformanceNavigationTiming 兩規范,應該以哪個為主?2)W3C Timing 規范 和 web-vitals 應該如何協作?
W3C 的 PerformanceTiming 和 PerformanceNavigationTiming 兩規范,應該以哪個為主?
PerformanceTiming:已被最新 W3C 標準廢棄,不過當前主流瀏覽器仍支持,舊瀏覽器支持好,兼容度高。
PerformanceNavigationTiming:最新標準隨 Navigation Timing Level 2 于 2019 年推出,Navigation Timing Level 2 目的是代替涵蓋 PerformaceTiming 的 Navigation Timing Level 1。
變更點:
- 整合 PerformanceTiming 和 PerformanceNavigation 功能。
- 廢棄因各瀏覽器廠商實現不一,指導意義不足的 domLoading 節點。
- 添加 ServiceWorker 相關節點。
- 各屬性節點時間使用高精度、以 startTime 為起點的相對時間。
優點:
- 使用高精度的相對時間,避免因用戶端系統時間更改而導致后續節點值不準。
- 支持 ServiceWorker 相關統計。
缺點:
- 瀏覽器兼容性不足。
結論:
從 Can I Use 統計兩者兼容度僅差 2.67%,但是從我們實際用戶分布來看,使用 PerformanceNavigationTiming,用戶兼容度下降 12%,難以接受。所以我們以 PerformanceNavigationTiming 為主,如瀏覽器不支持,則使用 PerformanceTiming。兩者數據格式差異不大,忽略 PerformanceTiming 中 domLoading 節點,使用 PerformanceTiming 時認為瀏覽器不兼容 workStart 節點即可。
W3C Timing 規范 和 web-vitals 應該如何協作?
PerformanceNavigationTiming ( 以下簡稱 Timing ): 基于 W3C 規范,著重從瀏覽器處理過程角度衡量頁面性能,以下簡稱 Timing。
優點:
- 瀏覽器兼容性好瀏覽器兼容性好。
- 數據豐富,指標全面。即包含各階段耗時,如:Unload、Redirect、DNS、TCP、SSL、Response、DomContentLoadedEvent 和 LoadEvent;還支持顯示頁面運行到各節點時的耗時,如:workStart、fetchStart、requestStart、domInteractive 和 domComplate;也可以根據所給節點值,計算 DCL ( DomContentLoaded ) 、window.load 事件或者 PageLoad(頁面加載)的耗時。
缺點:
- 缺乏關鍵指標。雖然指標多、全,但是不夠直觀,很難表達用戶體驗效果。
web-vitals: 目前含 6 個指標:TTFB、FCP、LCP、FID、INP 和 CLS,其中 FID 將被 INP 代替。TTFB、FCP 和 LCP 反映頁面加載性能,FID 與 INP 代表頁面交互體驗,CLS 表示頁面視覺穩定性。僅 6 個指標,就能支持對頁面加載、交互和視覺穩定方面的評估。不過 web-vitals 部分指標源頭還是來自于 W3C 制定的 LargestContentfulPaint、LayoutShift、PerformanceEventTiming 和 PerformancePaintTiming 等規范,不過兼容性更好、整體性更強。
優點:
- 指標簡明、精練、易懂。
- 自帶基線,能根據指標,判斷頁面性能優劣。
缺點:
- 瀏覽器兼容不足,尤其在 IOS 端。
- LCP 可以偽造。做法:給頁面添加大尺寸白底圖,該圖加載時間大概率就是 LCP 值,但是該 LCP 值并沒有任何業務意義
- 受限于 LCP、CLS 原理,對采集指標時機有一定要求,后面會詳細介紹。
述求
真實、客觀、全面衡量頁面性能。
結論
同時采集 Timing 和 web-vitals 數據,帶來好處有:
- 指標豐富、數據全面,既能利用 Timing 站在瀏覽器角度反映各節點、各階段處理耗時,也能通過 web-vitals 直觀表達用戶視覺體驗。建議先通過 web-vitals 直觀判斷頁面性能,再通過 Timing 再進一步分析,達到綜合考慮、全面分析,減少因瀏覽器兼容不足、LCP 造假等情況下,誤判頁面性能。
- 結合 Timing 和 web-vitals 數據,更容易定位問題。如:web-vitals 采集到的 TTFB 慢,可以通過 Timing 定位到具體慢在 Unload、Redirect、DNS、TCP、SSL 哪個階段。
- 解決 web-vitals 老瀏覽器兼容不足的問題。如果瀏覽器不支持 web-vitals, 可以通過 DCL、window.load 事件或者 PageLoad(頁面加載)的耗時來判斷頁面性能。
小節:RUM 技術選型,同時采集 PerformanceNavigationTiming 和 web- vitals。如果瀏覽器不兼容 PerformanceNavigationTiming,則以 PerformanceTiming 代替。
采集哪些指標
我們的需求是:在盡可能不影響頁面性能,既能客觀、全面衡量頁面性能,又能幫助研發同學快速定位性能瓶頸點。具體包含三方面需求:1) 指標要全面客觀;2) 能發現慢頁面的瓶頸點;3) 滿足前面兩需求前提下,盡可能不影響頁面性能。
指標要全面客觀
首先,我們采集了 web- vitals 六個指標,效果如下:
谷歌計劃于 2024 年用 INP 替換 FID,FID 體現第一次交互的延遲時間,INP 表示所有交互中最長的延遲時間。我們認為 FID 和 INP 都有各自使用場景,同時保留并不矛盾。
其次,我們對 PerformanceNavigationTiming 做了加工處理,效果如下:
與下面的 W3C 示例圖不同:
原因在于:
- 實際頁面運行過程中,各階段并不一定如上圖那樣串行運行。存在 responseEnd 耗時大于 domLoading 的情況。
- HTTP Cache 階段并無起止時間節點,只能表明發生在 fetchStart 和 domainLookUpStart 節點之間。
- ServiceWorkerInit、ServiceWorkerFetchEvent 和 Request 階段只有起始節點,沒有終止節點,無法統計階段耗時。對于 Request 階段不能以 responseStart 作為終止節點,因為內容在網絡中是分幀傳送的,不一定可以一次傳輸整個頁面內容。
- Processing 階段以 domInteractive 為起點,不符合客觀規律,頁面執行到 domInteractive 時候 DOM is ready,所以 Processing 階段無法代表頁面處理過程。
所以我們結合 W3C 示例圖,以點、段和線的方式,展示真實的頁面運行過程:
- 點:指不存在終止節點的節點,含:workStart、fetchStart、requestStart、domInteractive 和 domComplete,用白色圓點表示。
- 段:指真實存在起始和終止節點的處理階段,如 unload 階段值為:unloadEnd - unloadStart。同理于 redirect、DNS、TCP、SSL、Response、domContentLoadedEvent 和 loadEvent,用藍色柱狀圖表示。
- 線:含頁面加載過程中觸發的事件,如 DCL ( DomContentLoaded ) 、window.load。另外我們自定義 PageLoad 事件,表示整個頁面加載耗時,值為: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
此外,為了更全面體現頁面性能,還采集和統計了如下輸入:
- 小概率 (1%) 的采集完整 PerformanceEntry 數據。PerformanceEntry 包含 LargestContentfulPaint、LayoutShift、PerformanceEventTiming、PerformanceLongTaskTiming、PerformanceNavigationTiming、PerformancePaintTiming、PerformanceResourceTiming、PerformanceServerTiming 等方面數據,既包含頁面本身性能指標,還涵蓋資源、網絡、緩存、JS 長阻塞任務、慢執行事件等多方面信息,對評估頁面性能,判斷慢頁面瓶頸點很有幫助。考慮到大部分頁面內容較多,導致 PerformanceEntry 集合條數太大,要是 100%采集上報,對帶寬、存儲、查詢性能都有較大影響,所以只能小概率采集。
- 頁面導航類型,取值于 PerformanceNavigationTiming.type,判斷頁面是首次加載還是刷新重載等。
- 按資源類型,統計各類資源個數、總傳輸體積和總耗時。
- 按域名,統計各域名資源個數、總傳輸體積和總耗時。
能發現慢頁面瓶頸點
我們參考Lighthouse 50 分線 和 HTTP Archive 站點統計數據,根據應用類型是 PC 或 M 來制定慢頁面標準,具體閾值如下:
針對慢頁面,我們除了采集上節提到的 PerformanceNavigationTiming、web- vitals、小概率的完整 PerformanceEntry 數據和統計數據外,我們還會采集:
- TOP N 慢資源,做法:取 duration 值最大的 N 個 PerformanceResourceTiming 類型的 PerformanceEntry。
- 長任務,指占用 UI 線程大于 50 毫秒的任務。做法:采集所有 PerformanceLongTaskTiming 類型的 PerformanceEntry。不過當前大部分瀏覽器無法提供長任務所在的腳本地址( containerSrc )和方法名稱( containerName ),采集這部分數據,只能判斷長任務是否發生?發生的次數。PerformanceLongTaskTiming 內容如下:
- 慢事件,指處理時間超過 104ms 的交互事件,做法:采集所有 PerformanceEventTiming 類型的 PerformanceEntry。
- 頁面跳轉次數,值為:PerformanceNavigationTiming.redirectCount,可以輔助分析 Redirect 階段耗時多的原因。
- CLS 和 LCP 值大于慢頁面閾值時,記錄其關聯的元素。
不影響頁面性能
RUM 必須通過入侵頁面,在頁面引入 JS SDK 來實現,不可避免地影響頁面性能。作為一個發現和分析頁面性能的工具,不應該加重頁面性能問題。為了將性能影響降到最低,我們做了兩方面工作:
異步加載 JS SDK:頁面只引入功能單一、體積小的 JS 頭文件,待頁面到達 DomContentLoaded 事件后,以動態 script 方式異步加載功能完整的 JS 主文件。
減少帶寬占用:
- 抽樣上報:慢頁面必須上報,非慢頁面抽樣上報,默認抽煙比例為 30%,減少上報次數。
- 減少上報數據體積:全量的 PerformanceEntry 數據可以完整體現頁面性能,不少頁面動輒超過白條 PerformanceEntry 數據,體積過大,所以只能小概率采集全量 PerformanceEntry 數據,計算和采集 PerformanceEntry 的統計數據。
綜上所述我們采集指標主要兩大類:PerformanceEntry 和 web-vitals。
SPA 應用非首頁性能該如何評估?
采集上述指標,已經可以較為客觀全面評估常規頁面和 SPA 應用首頁的頁面性能。但是 SPA 應用非首頁不是瀏覽器標準,在 SPA 路由切換過程中:
- 瀏覽器僅會執行 History.replaceState()方法,不會也不該重新生成 PerformanceNavigationTiming 數據。
- 多數 PerformanceEntry 數據包含 SPA 首頁以來所有路由切換頁面的性能指標。以 PerformanceResourceTiming 為例,無法通過 History.replaceState()方法拿到真實路由切換的時機,排除 PerformanceResourceTiming 集合中的歷史數據,從而獲取當前路由的 PerformanceResourceTiming 數據。因為各前端框架在 SPA 路由切換過程中,大多數會先執行其框架內部邏輯,而后再觸發 History.replaceState()方法,所以 History.replaceState()方法觸發時間晚于路由切換的執行時間。
- web-vitals 暫時也不支持采集 SPA 非首頁路由切換后的性能指標。
所以,對于上述指標 SPA 非首頁無法或無法準確拿到,所以我們暫不評估 SPA 非首頁性能。
針對業內 SPA 非首頁性能難評估的情況,字節 WebPro 創造性地推出 SPA_LOAD 的概念,基本邏輯為:以觸發 history.replaceState() 方法為起點,通過 MutationObserver 監聽 dom 變更、資源加載、請求發送等變更事件來尋找一個頁面達到穩定態的時間為終點,通過計算起終點之間的耗時,來衡量 SPA 非首頁的頁面性能。SPA_LOAD 類似于常規頁面 onload 事件,但是起始時間比真實路由切換時間晚,到終止時間時頁面可能已經加載完畢,略有不足,不過已是當前最佳的方案,后面我們可能引入。
采集指標時機
只有采集真實、準確的指標值,才能真實反映頁面性能,反之,可能誤導產研同學,錯誤評估真實的頁面性能。所以選擇采集指標時機有幾大原則:
- 指標準,最關鍵是要保證指標是準的,不準不如不采。
- 樣本多,上報可靠,部分指標,如 CLS、INP、PerformanceEventTiming 等,越晚采集值越準,但是越晚采集,留給上報的時間越少,數據上報失敗的概率越大,為了盡量多采集數據樣本,我們不能等到頁面關閉時再采集指標、提交上報。
- 公平,部分指標,如 CLS、INP、LCP 等,隨著頁面打開時間邊長,值可能也跟著變大。對于這類指標,我們只能保證數據”樣本多“的前提下,選擇一個相對合理、對“所有項目”都公平的采集時機。
- 一次上報,web-vitals 中部分指標如:LCP、CLS、INP,每次變更都會觸發其回調函數,谷歌官方建議每次指標值變更都采集上報。這種處理邏輯,指標值是更準,但是占用太多前端的連接、帶寬和 CPU 資源,也嚴重加大后端接收程序的處理難度,不是各合理均衡的選擇。所以我們要找到一個合適的采集時機,一次采集并上報所有的性能指標。
那么如何確定采集時機?我們得先分析 PerformanceEntry 和 web-vitals 兩類指標數據得準確生成時間:
對于 PerformanceEntry 數據,onload 事件觸發時,頁面已接近加載完畢,PerformanceEntry 中影響首屏加載的絕大部分指標數據已經生成。未生成的數據對評估頁面性能影響不大,如:PerformanceNavigationTiming 中的 loadEventEnd 指標值。所以我們認為 onload 事件觸發件時,可以采集 PerformanceEntry 指標。
web-vitals 中各指標生成原理不一,onload 事件觸發時:
- TTFB、FCP 指標已生成且不會變,可以采集。
- LCP 對應的最大元素大概率已加載完畢,所以我們認為這時候 LCP 值大概率是準的,可以采集。
- CLS 值無法確定是否準確,其計算邏輯為:頁面打開后每 5s 作為一個 session 窗口,累加該窗口內產生的偏移值即是 CLS 值,如果下一個 session 窗口的 CLS 值大于上一個 session 窗口,則替換。所以對于 CLS 指標來說,打開頁面 5S 后、最好 5S 或其整數倍時采集,比較合適,對”所有項目“也比較公平。
- FID、INP 也無法確定是否準確,它們依賴用戶交互操作后才生成,交互操作含:點擊、輸入、拖放、觸摸等事件。FID 是第一次交互的延遲時間,INP 取多次交互操作中延遲時間最大的值。這兩指標都依賴于用戶操作,INP 可能會隨著用戶操作次數變多而值變大,所以任何時間都沒法保證準確拿到這兩指標值。
基于上述考慮,我們認為至少要滿足:觸發 onload 事件或打開頁面 5s 之一條件時,才能保證 PerformanceEntry 或部分 web-vitals 指標值準確,采集才有意義。在追求”樣本多“的原則下,結合 RUM SDK 是 onload 事件后異步加載的實際情況,我們針對頁面是否被正常關閉前提下,總共設置了三種采集時機,其特點如下:
為了避免采集指標影響頁面性能,我們異步加載 RUM JS SDK,web-vitals 中各指標默認僅支持異步回調,異步加載再異步回調,導致采集時機時仍可能無法拿到各指標值,所以我們對 web-vitals 源碼做了改造,支持同步獲取各指標值。
上報方式
采集到指標后,需要選擇恰當上報方式,將指標可靠的發送到后端。上報方式包含兩個部分:上報機制和上報時機。
選擇合適的上報機制,首先,要滿足功能需求,瀏覽器兼容度高,對數據大小最好沒限制;其次,能感知上報請求異常,便于上報重試,進而提高上報可靠性;最后,客戶端支持設置超時時間,避免長時間占用忘了連接,加大后端服務壓力。常見上報機制有四種,分別是:Image、XMLHttpRequest、sendBeacon、Fetch API。其特點如下:
Image | XMLHttpRequest | sendBeacon | Fetch | |
基本原理 | 創建一個 1 像素、隱藏的 img DOM,將上報地址和上報內容包含在 img 的 src 中。上報成功則返回 200 狀態碼 | 利用瀏覽器內置對象 XMLHttpRequest 上報數據 | 使用專門設計用于發送分析數據的 navigator.sendBeacon()方法,以異步發送 HTTP POST 請求的方式將分析數據提交到后端 | fetch 是一個現代的、基于 Promise 的用于發送 HTTP 請求的 API |
瀏覽器兼容性 | 高 | 高 | 中,不支持 IE | 中偏低,不支持 IE |
數據大小限制 | 小于 8K 各瀏覽器大小限制不一,且受制于 CDN、后端代理和 web 服務器,默認值常為 8K。8K 指用 URI 編碼后的長度 | 用 POST 請求,無限制 | 有,部分瀏覽器小于 64K | 用 POST 請求,無限制 |
感知上報異常 | 部分支持。 請求返回狀態碼為 404 或 204 時會觸發 img onerror 事件。狀態碼大于等于 400,不會觸發 onerror 事件,如 400、500、502 和 504 等。 | 支持 | 不支持。 sendBeacon()返回值,只能表示瀏覽器是否發出請求 | 支持 |
可設置超時 | 不可以,依賴服務端的設置 | 可以 | 不可以 | 可以 |
優點 | 使用簡單、兼容度高 | 功能強大,靈活易擴展 無大小限制,兼容度高 | 使用簡單,可靠性高 頁面關閉時,仍可發送 | 相比于 XMLHttpRequest,使用更簡介、功能更強大 |
缺點 | 數據大小有限制,難感知上報異常 | 代碼編寫略復雜 跨域處理要留意 | 無法感知上報異常,函數返回值 true、false 只能代表是否發送成功 | 同 XMLHttpRequest 瀏覽器兼容度最低 |
適用場景 | 上報數據小,可靠性要求不高 | 功能需求多 建議以 POST 方式用 text/plain 或 application/x-www-form-urlencoded 格式上報,CORS 預驗證 | 需要在頁面關閉時,上報數據 | 同 XMLHttpRequest,更適用于瀏覽器分布較新的終端 |
上述結論:依賴于 chrome114
相比于 Fetch,XMLHttpRequest 功能幾乎一致,兼容性更高;與 Image 對比,XMLHttpRequest 具有兼容度高、數據大小沒限制、能感知異常和可設置超時時間等優勢;XMLHttpRequest 是頁面正常(未關閉)情況下,發送指標數據的首選上報機制。至于 sendBeacon,雖然存在諸多不足,但是頁面關閉時仍可以上報數據,成功率還較高,適合作為在頁面關閉時,發送尚未發送的指標數據的上報機制。
既然選擇了 sendBeacon 作為頁面關閉時發送指標數據的上報機制,那該如何判斷頁面被關閉?傳統方案是監聽 unload 或 beforeunload 事件,該方案存在兩個不足:
- 不能滿足功能需求。手機端用戶離開頁面時,更習慣將瀏覽器隱藏,而不是關閉瀏覽器。隱藏頁面時,不會觸發 unload 和 beforeunload 事件。
- 性能有損耗。部分瀏覽器,監聽到 unload 或 beforeunload 事件后,無法使用 bfcache,導致頁面性能降低。
更合適、更現代的方案是監聽 pagehide 或 visibilitychange===hiden 事件,該方案除了避免傳統方案存在的兩不足,兼容度也會更高。對于 SPA 項目我們不采集非首頁性能指標,觸發History.replaceState()方法也算離開頁面。
綜上所述,整體上報機制為:1)頁面正常(未關閉),到采集時機時,SDK 采集性能指標數據,使用 XMLHttpRequest 機制上報;2)通過監聽 pagehide 或 visibilitychange===hiden 事件,當頁面被關閉時,如果滿足任一采集時機條件,則立即采集指標,使用 sendBeacon 機制上報。
整體方案
綜上所述,我們整理 RUM 實施大綱如下:
實際編碼過程中,具體處理流程如下:
優缺點
在實施過程中,我們總結 RUM 優缺點如下:
RUM 架構設計復雜,實施成本較高,由于是技術剛需,只能投入資源,努力做好。
針對 無診斷結果和優化建議 的缺點,可以結合 SYN,取長補短,利用 SYN 診斷慢頁面性能瓶頸點分布。
對于 無評分,沒法判斷頁面性能優劣 的問題,我們分三步走:首先,制定慢頁面標準,判斷單次頁面是否快慢,標準值前文已有描述;其次,統計該頁面各重要指標的 AVG、TP50、TP90、TP99 值,全面評估頁面所有請求的性能分布;最后,我們會對頁面所在的應用進行評分,直接告訴研發同學,該應用性能優劣,應用評分具體做法,會在下面《建立評分體系》章節細講。
三、整體架構設計
前文深入分析了 SYN 和 RUM 各自特點、使用方法及優缺點等,我們發現 SYN 和 RUM 各有所長、無法替代,最好同時引用 SYN 和 RUM,構建體系化性能監控架構,提供性能監控和性能分析工具鏈,支持產研同學在 devpos 各階段中發現和定位頁面性能問題。
在編碼、構建和測試階段,研發同學可以利用 SYN 來做頁面性能測試,判斷頁面性能是否達標?如果頁面性能有問題,再利用 SYN 診斷性能問題,獲得優化建議。此舉解決前端頁面長期以來,前端頁面做性能測試難、交付頁面質量無標準等痛點。應用部署后,再利用 RUM 采集真實用戶頁面性能,評估真實頁面性能,如果還存在慢頁面,仍可以使用 SYN 定位慢頁面性能瓶頸點,并利用診斷結果和優化建議,提高優化效率。除此之外,SYN 還可以用來做競品對比,達到知己知彼、快競爭對手一步的目的。
有了 SYN 和 RUM,我們可以構建在線持續優化慢頁面的閉環,如上圖。RUM 負責采集真實用戶產生的慢頁面,經后臺存儲、聚合,自動將 TOPN 的慢頁面創建 SYN JOB,待 JOB 運行完畢,將診斷結果和優化建議以告警防止通知研發同學,研發同學利用 SYN 優化建議,再利用 devtools、webpack 等工具,改進頁面,交付高質量頁面,降低慢頁面的頻次。如此循環迭代,持續優化應用頁面性能,最終應用能達到極致性能。
三、建立評判體系
引入 SYN,自研 RUM SDK,采集到眾多 SYN 和 RUM 指標數據后,我們將著手建立評判體系,評估各應用、團隊、部門,乃至整個公司的性能情況,輸出少數幾個關鍵指標和評分,直觀告訴各層級、各角色員工其所在組織及同級組織的頁面性能情況,通過得分和同級對比,評判是否要優化頁面性能?
建立評判體系時我們秉持著:既要突出重點、關鍵指標,同時還能全面、綜合、客觀真實地反映頁面性能 的原則。所以我們將評判體系分為兩大塊,其一,展示最關鍵的性能指標。其二,輸出各指標、應用、團隊、部門及公司層級的性能評分和層級。
展示最關鍵的性能指標
我們從 web-vitals 和 performanceNavigationTiming 中各選一個最能代表頁面性能的指標,分別為:DCL 和 LCP。LCP 兼容度不高且可能被偽造,DCL 既能代替 LCP 部分反映首屏性能且兼容度高、難以偽造,和 LCP 相輔相成,最能體現頁面性能。
TP90 代表 90%用戶的體驗下限,與 AVG、TP50、TP75 比,覆蓋和統計更廣的用戶,還能屏蔽頁面在手機端特殊網絡環境下,產生的少數臟數據,更具有代表性。
輸出各級評分
應用性能評分
為了全面、綜合和客觀的評估應用頁面性能。我們將選擇各維度具有代表性指標,參考 HTTP Archive 給予的業內指標分布,根據應用特性,如應用類型( PC 或 M 端 )、終端用戶( C 端用戶、B 端客戶和內部員工),設立不同的評分基線,算出各指標得分。再根據各指標重要程度設置權重,通過加權平均算法,求得應用性能評分。流程如下:
獲取應用性能分過程中涉及幾個重要流程:1) 指標篩選及權重設置;2) 選擇評分算法;3) 確立指標基線;4) 使用加權平均算法計算應用性能分。下面逐一介紹。
指標篩選及權重設立
此過程中,我主要考慮兩點:
全面綜合考慮。頁面性能涵蓋多方面,傳統上只用首字節、白屏、首屏時間等少數指標來衡量,較為片面,不夠客觀。我們認為評判頁面性能應該涵蓋各維度指標,如:頁面加載、交互體驗和視覺體驗。此外我們還引入慢 API 比例的概念,API 請求比例指頁面打開后 API 耗時超過 3s 的請求比例,慢 API,即可能影響首屏加載耗時,也會影響交互過程中的用戶體驗。為了讓研發同學關注慢頁面、將在線 SYN 作為日常開發性能評估工具,我們將 SYN 評分也作為權重指標,后臺系統每天會統計訪問次數 TOP10 的慢頁面并自動創建 SYN 定時任務,待任務執行、分析完畢后,將優化建議和診斷結果通知研發同學。SYN 評分項,包含性能分和最佳實踐分,兩者都是百分制。
突出重點。提高重要指標的權重比。如:加載指標用于衡量頁面能不能用,最為關鍵,所以賦予權重占比最大。LCP 是最重要的加載指標,權重占比也相應提高。由于 LCP 本身不一定完全合理且可能被偽造,所以評判頁面加載性能時,還引入 DCL、FCP、TTFB、WindwLoad 和 PageLoad 等加載指標。該做法,優點:指標多,維度廣、角度大、更全面和更客觀準確;缺點:增加評判系統復雜度和難度。
基于上述兩點考慮,我們指標篩選結果和權重占比設置,如下圖:
各指標以其 TP90 統計值,參與評分運算。
選擇評分算法
評分算法主要參考 Lighthouse 評分曲線模型,基本原理是:設置兩個控制點,通常是 TP50 和 TP90,即得 50 或 90 分時的指標值點,然后根據這兩個控制點,生成對數正態曲線,通過該曲線可以獲得任一指標值對應的得分。下圖是 M 端 LCP 的評分曲線:
m 表示中位數,圖中 m 值為 4000ms,表示當 LCP 值為 4000ms 時,得 50 分;同理 p10 為 2520ms,LCP 值為 2529ms 時,得 90 分。設置 m 和 p10 后,會生成右邊的評分曲線模型,根據該模型可以獲得 LCP 值從 0 到正無窮時的得分。
確立指標基線
確立指標基線是為了給評分算法提供兩個控制點,即 m 和 p10 的值。確立方法有三種:
- 直接借用 Lighthouse 配置。以 Lighthouse 對應指標的 50 分和 90 分閾值為 m 和 p10 控制點值,如 web-vitals 中各指標。
- 參考 HTTP Archive 統計數據,以統計數據中的 p10、p75 值為 m 和 p10 控制點值。如 performanceNavigationTiming 各指標。
- 自建基線。少數指標基線無法從上述兩種方法確立,只能自建基線。具體做法:以當前后臺系統拿到的數據為樣本,以樣本的 tp75 和 tp95 值為 m 和 p10 控制點值。適用于慢 api 比例指標。
確立基線過程中,應考慮應用價值和研發要求的不同,根據應用特性,有針對性的設置。首先,PC 端和 M 端類型的應用,要設置不同的指標基線,所幸 Lighthouse 和 HTTP Archive 都提供 PC 端和 M 端的配置參考;其次,根據應用實際終端用戶類型,有針對性的調整閾值。C 端和 B 端應用,直接產生業務價值,性能要求要比內部應用高,兩控制點值應該更低。
使用加權平均算法計算應用性能分
根據指標 tp90 值、指標基線和評分算法,求得該指標的百分制得分。
使用加權平均算法求應用性能分,結果 = (Σ (指標tp90值 × 指標權重)) / (Σ 權重) ,其中:Σ 表示求和。
各級組織評分
至于求各級組織,含團隊、部門及公司的性能分,則根據其管轄的應用個數、應用性能分及應用權重,仍使用加權平均算法獲取組織分。流程如下:
求組織性能分的難點是:如何設置應用權重?我們主要參考應用的 PV 區間和應用級別。PV 層級越大、應用級別越高,權重越大。具體配置參考如下:
PV區間中的PV 值指采用 PV,而非真實 PV,采用 PV=采集到 RUM 數據量/抽樣比例。
經過上述步驟,我們能獲得應用性能分,以及各級組織的性能分,如團隊性能分、部門性能分及之家性能分,展示效果如下:
性能分參考lighthouse標準,50分以上算合格,90分以上才算優秀。
四、總結
通過頁面性能監控和評判體系建設,我們既有原始頁面性能數據,又有聚合統計值,還有最終評分。通過評分、統計和原始數據,打通了發現、定位和分析性能問題的鏈路。研發同學可以通過評分直觀判斷應用性能優劣是否需要優化?如果需要優化,再通過聚合統計數據,分析應用瓶頸點;定位具體瓶頸點時,可以查看明細數據,輔助分析產生瓶頸點的具體原因;改進后可以通過通過統計查看優化效果,最終反映到提高評分上。
受限于篇幅,本文僅能介紹頁面性能監控和評判體系建設相關的實踐。一個完整的頁面性能監控系統,還應該包含:監控、報警、優化、治理等模塊,不僅僅只是指標,能度量頁面性能,發現其中性能瓶頸點,幫助研發同學提升優化效率,還要治本,通過構建一系列前端工具鏈,改進交付過程,通過規范、工具和流程,從源頭上提高頁面交付質量,避免將問題帶到線上,先于用戶發現性能問題。
五、參考文獻
Web Vital Metrics for Single Page Applications
一個收集和分析網站性能數據的項目,旨在幫助 Web 開發者了解互聯網的技術趨勢以及性能優化的最佳實踐。