令程序員頭疼的性能問題,這一款性能分析工具幫你實(shí)時(shí)監(jiān)控(軟件性能監(jiān)控)
作者:basinwang,騰訊 PCG 前端開發(fā)工程師
大型項(xiàng)目容易遇到性能問題,一般來說,當(dāng)我們遇到性能瓶頸的時(shí)候,才會(huì)開始去進(jìn)行相應(yīng)的分析。分析的方向除了業(yè)務(wù)本身的特點(diǎn)相關(guān)之外,常見的還可以借助一些工具來發(fā)現(xiàn)問題。本文主要介紹前端性能分析可以怎么走~
前端性能分析工具(Chrome DevTools)
一般來說,前端的性能分析通常可以從時(shí)間和空間兩個(gè)角度來進(jìn)行:
- 時(shí)間:常見耗時(shí),如頁面加載耗時(shí)、渲染耗時(shí)、網(wǎng)絡(luò)耗時(shí)、腳本執(zhí)行耗時(shí)等
- 空間:資源占用,包括 CPU 占用、內(nèi)存占用、本地緩存占用等
那么,下面來看看有哪些常見的工具可以借來用用。由于我們的網(wǎng)頁基本上跑在瀏覽器中,所以基本上大多數(shù)的工具都來源于瀏覽器自身提供,首選工具自然是 Chrome DevTools。本文我們也主要圍繞 Chrome DevTools 來進(jìn)行說明。
Lighthouse
Lighthouse 的前身是 Chrome DevTools 面板中的 Audits。在 Chrome 60 之前的版本中, 這個(gè)面板只包含網(wǎng)絡(luò)使用率和頁面性能兩個(gè)測量類別,從 Chrome 60 版本開始, Audits 面板已經(jīng)被 Lighthouse 的集成版取代。而在最新版本的 Chrome 中,則需要單獨(dú)安裝 Lighthouse 拓展程序來使用,也可以通過腳本來使用。
架構(gòu)
Lighthouse 架構(gòu)
下面是 Lighthouse 的組成部分:
- 驅(qū)動(dòng)(Driver):和 Chrome Debugging Protocol 進(jìn)行交互的接口
- 收集器(Gatherers):使用驅(qū)動(dòng)程序收集頁面的信息,收集器的輸出結(jié)果被稱為 Artifact
- 審查器(Audits):將 Artifact 作為輸入,審查器會(huì)對其運(yùn)行測試,然后分配通過/失敗/得分的結(jié)果
- 報(bào)告(Report):將審查的結(jié)果分組到面向用戶的報(bào)告中(如最佳實(shí)踐),對該部分應(yīng)用加權(quán)和總體然后得出評分
主要功能
Lighthouse 會(huì)在一系列的測試下運(yùn)行網(wǎng)頁,比如不同尺寸的設(shè)備和不同的網(wǎng)絡(luò)速度。它還會(huì)檢查頁面對輔助功能指南的一致性,例如顏色對比度和 ARIA 最佳實(shí)踐。
在比較短的時(shí)間內(nèi),Lighthouse 可以給出這樣一份報(bào)告(可將報(bào)告生成為 JSON 或 HTML):
Lighthouse 架構(gòu)
這份報(bào)告從 5 個(gè)方面來分析頁面:性能、輔助功能、最佳實(shí)踐、搜索引擎優(yōu)化和 PWA。像性能方面,會(huì)給出一些常見的耗時(shí)統(tǒng)計(jì)。除此以外,還會(huì)給到一些詳細(xì)的優(yōu)化方向。
如果你希望短時(shí)間內(nèi)對你的網(wǎng)站進(jìn)行較全面的評估,可以使用 Lighthouse 來跑一下分?jǐn)?shù),確定大致的優(yōu)化方向。
Performance 面板
Performance 面板同樣有個(gè)前身,叫 Timeline。該面板用于記錄和分析運(yùn)行時(shí)性能,運(yùn)行時(shí)性能是頁面運(yùn)行時(shí)(而不是加載)的性能。
使用步驟
Performance 面板功能特別多,具體的分析也可以單獨(dú)講一篇了。這里我們簡單說一下使用的步驟:
- 在隱身模式下打開 Chrome。隱身模式可確保 Chrome 以干凈狀態(tài)運(yùn)行,例如瀏覽器的擴(kuò)展可能會(huì)在性能評估中產(chǎn)生影響。
- 在 DevTools 中,單擊“Performance”選項(xiàng)卡,并進(jìn)行一些基礎(chǔ)配置(更多參考官方說明)。
- 按照提示單擊記錄,開始記錄。進(jìn)行完相應(yīng)的操作之后,點(diǎn)擊停止。
- 當(dāng)頁面運(yùn)行時(shí),DevTools 捕獲性能指標(biāo)。停止記錄后,DevTools 處理數(shù)據(jù),然后在 Performance 面板上顯示結(jié)果。
主要功能
關(guān)于 Performance 怎么使用的文章特別多,大家網(wǎng)上隨便搜一下就能搜到。一般來說,主要使用以下功能:
- 查看 FPS 圖表:當(dāng)在 FPS 上方看到紅色條形時(shí),表示幀速率下降得太低,以至于可能損害用戶體驗(yàn)。通常,綠色條越高,F(xiàn)PS 越高
- 查看 CPU 圖表:CPU 圖表在 FPS 圖表下方。CPU 圖表的顏色對應(yīng)于性能板的底部的 Summary 選項(xiàng)卡
- 查看 火焰圖:火焰圖直觀地表示出了內(nèi)部的 CPU 分析,橫軸是時(shí)間,縱軸是調(diào)用指針,調(diào)用棧最頂端的函數(shù)在最下方。啟用 JS 分析器后,火焰圖會(huì)顯示調(diào)用的每個(gè) JavaScript 函數(shù),可用于分析具體函數(shù)
- 查看 Buttom-up:此視圖可以看到某些函數(shù)對性能影響最大,并能夠檢查這些函數(shù)的調(diào)用路徑
具體要怎么定位某些性能瓶頸,可以參考官方文檔系列文章,這里就不詳細(xì)介紹啦。
Performance Monitor
打開 Chrome 控制臺后,按組合鍵ctrl p(Mac 快捷鍵為command p),輸入> Show Performance Monitor,就可以打開 Performance Monitor 性能監(jiān)視器。主要的監(jiān)控指標(biāo)包括:
- CPU usage:CPU 占用率
- JS head size:JS 內(nèi)存使用大小
- DOM Nodes:內(nèi)存中掛載的 DOM 節(jié)點(diǎn)個(gè)數(shù)
- JS event listeners:事件監(jiān)聽數(shù)
- …:其他等等
大多數(shù)情況下,我們在進(jìn)行性能優(yōu)化的時(shí)候,使用上面一些工具也足以確定大致的優(yōu)化方向。更多的細(xì)節(jié)和案例,就不在這里詳述了。
前端性能監(jiān)控
除了具體的性能分析和定位,我們也經(jīng)常需要對業(yè)務(wù)進(jìn)行性能監(jiān)控。前端性能監(jiān)控包括兩種方式:合成監(jiān)控(Synthetic Monitoring,SYN)、真實(shí)用戶監(jiān)控(Real User Monitoring,RUM)。
合成監(jiān)控
合成監(jiān)控就是在一個(gè)模擬場景里,去提交一個(gè)需要做性能審計(jì)的頁面,通過一系列的工具、規(guī)則去運(yùn)行你的頁面,提取一些性能指標(biāo),得出一個(gè)審計(jì)報(bào)告。例如上面介紹的 Lighthouse 就是合成監(jiān)控。
合成監(jiān)控的使用場景不多,一般可能出現(xiàn)在開發(fā)和測試的過程中,例如結(jié)合流水線跑性能報(bào)告、定位性能問題時(shí)本地跑的一些簡單任務(wù)分析等。該方式的優(yōu)點(diǎn)顯而易見:
- 可采集更豐富的數(shù)據(jù)指標(biāo),例如結(jié)合 Chrome Debugging Protocol 獲取到的數(shù)據(jù)
- 較成熟的解決方案和工具,實(shí)現(xiàn)成本低
- 不影響真實(shí)用戶的性能體驗(yàn)
真實(shí)用戶監(jiān)控
真實(shí)用戶監(jiān)控,就是用戶在我們的頁面上訪問,訪問之后就會(huì)產(chǎn)生各種各樣的性能指標(biāo)。我們在用戶訪問結(jié)束的時(shí)候,把這些性能指標(biāo)上傳到我們的日志服務(wù)器上,進(jìn)行數(shù)據(jù)的提取清洗加工,最后在我們的監(jiān)控平臺上進(jìn)行展示的一個(gè)過程。
我們提及前端監(jiān)控的時(shí)候,大多數(shù)都包括了真實(shí)用戶監(jiān)控。常見的一些性能監(jiān)控包括加載耗時(shí)、DOM 渲染耗時(shí)、接口耗時(shí)統(tǒng)計(jì)等,而對于頁面加載過程,可以看到它被定義成了很多個(gè)階段:
RUM 性能模型
而我們要做的,則是在力所能及的地方進(jìn)行打點(diǎn)、計(jì)算、采集、上報(bào),該過程常常需要借助 Performance Timeline API。將需要的數(shù)據(jù)發(fā)送到服務(wù)端,然后再對這些數(shù)據(jù)進(jìn)行處理,最終通過可視化等方式進(jìn)行監(jiān)控。因此,真實(shí)用戶監(jiān)控往往需要結(jié)合業(yè)務(wù)本身的前后端架構(gòu)設(shè)計(jì)來建設(shè),其優(yōu)點(diǎn)也比較容易理解:
- 完全還原真實(shí)場景,減去模擬成本
- 數(shù)據(jù)樣本足夠抹平個(gè)體的差異
- 采集數(shù)據(jù)可用于更多場景的分析和優(yōu)化
對比合成監(jiān)控,真實(shí)用戶監(jiān)控在有些場景下無法拿到更多的性能分析數(shù)據(jù)(例如具體哪里 CPU 占用、內(nèi)存占用高),因此更多情況下作為優(yōu)化效果來參考。這些情況下,具體的分析和定位可能還是得依賴合成監(jiān)控。
但真實(shí)用戶監(jiān)控也有自身的優(yōu)勢,例如 TCP、DNS 連接耗時(shí)過高,在各種環(huán)境下的一些運(yùn)行耗時(shí)問題,合成監(jiān)控是很難發(fā)現(xiàn)的。
性能分析自動(dòng)化
我們在開發(fā)過程中,也常常需要進(jìn)行性能分析。而前端的性能分析上手成本也不低,除了基本的頁面加載耗時(shí)、網(wǎng)絡(luò)耗時(shí),更具體的定位往往需要結(jié)合前面介紹的 Performance 面板、FPS、CPU、火焰圖等一點(diǎn)點(diǎn)來分析。
如果這一塊想要往自動(dòng)化方向發(fā)展,我們可以怎么做呢?
使用 Lighthouse
前面也有介紹 Lighthouse,它提供了腳本的方式使用。因此,我們可以通過自動(dòng)化任務(wù)跑腳本的方式,使用 Lighthouse 跑分析報(bào)告,通過對比以往的數(shù)據(jù)來進(jìn)行功能變更、性能優(yōu)化等場景的性能回歸。
使用 Lighthouse 的優(yōu)勢在于開發(fā)成本低,只需要按照官方提供的配置來調(diào)整、獲取自己需要的一些數(shù)據(jù),就可以快速接入較全面的 Lighthouse 擁有的性能分析能力。
不過由于 Lighthouse 同樣基于 CDP(Chrome DevTools Protocol),因此除了實(shí)現(xiàn)成本降低了,CDP 缺失的一些能力它也一樣會(huì)缺失。
Chrome DevTools Protocol
Chrome DevTools Protocol 允許第三方對基于 Chrome 的 Web 應(yīng)用程序進(jìn)行檢測、檢查、調(diào)試、分析等。有了這個(gè)協(xié)議,我們就可以自己開發(fā)工具獲取 Chrome 的數(shù)據(jù)了。
認(rèn)識 Chrome DevTools 協(xié)議
Chrome DevTools 協(xié)議基于 WebSocket,利用 WebSocket 建立連接 DevTools 和瀏覽器內(nèi)核的快速數(shù)據(jù)通道。
我們使用的 Chrome DevTools 其實(shí)也是一個(gè) Web 應(yīng)用。我們使用 DevTools 的時(shí)候,瀏覽器內(nèi)核 Chromium 本身會(huì)作為一個(gè)服務(wù)端,我們看到的瀏覽器調(diào)試工具界面,通過 Websocket 和 Chromium 進(jìn)行通信。建立過程如下:
- DevTools 將作為 Web 應(yīng)用程序,Chromium 作為服務(wù)端提供連接。
- 通過 HTTP 提取 HTML、JavaScript 和 CSS 文件。
- 資源加載后,DevTools 會(huì)建立與瀏覽器的 Websocket 連接,并開始交換 JSON 消息。
同樣的,當(dāng)我們通過 DevTools 從 Windows、Mac 或 Linux 計(jì)算機(jī)遠(yuǎn)程調(diào)試 Android 設(shè)備上的實(shí)時(shí)內(nèi)容時(shí),使用的也是該協(xié)議。當(dāng) Chromium 以一個(gè)–remote-debugging-port=0標(biāo)志啟動(dòng)時(shí),它將啟動(dòng) Chrome DevTools 協(xié)議服務(wù)器。
Chrome DevTools 協(xié)議域劃分
Chrome DevTools 協(xié)議具有與瀏覽器的許多不同部分(例如頁面、Service Worker 和擴(kuò)展程序)進(jìn)行交互的 API。該協(xié)議把不同的操作劃分為了不同的域(domain),每個(gè)域負(fù)責(zé)不同的功能模塊。比如DOM、Debugger、Network、Console和Performance等,可以理解為 DevTools 中的不同功能模塊。
使用該協(xié)議我們可以:
- 獲取 JS 的 Runtime 數(shù)據(jù),常用的如window.performance和window.chrome.loadTimes()等
- 獲取Network及Performance數(shù)據(jù),進(jìn)行自動(dòng)性能分析
- 使用 Puppeteer 的 CDPSession,與瀏覽器的協(xié)議通信會(huì)變得更加簡單
與性能相關(guān)的域
本文講性能分析相關(guān),因此這里我們只關(guān)注和性能相關(guān)的域。
1. Performance。從Performance域中Performance.getMetrics()可以拿到獲取運(yùn)行時(shí)性能指標(biāo)包括:
- Timestamp: 采取度量樣本的時(shí)間戳
- Documents: 頁面中的文檔數(shù)
- Frames: 頁面中的幀數(shù)
- JSEventListeners: 頁面中的事件數(shù)
- Nodes: 頁面中的 DOM 節(jié)點(diǎn)數(shù)
- LayoutCount: 全部或部分頁面布局的總數(shù)
- RecalcStyleCount: 頁面樣式重新計(jì)算的總數(shù)
- LayoutDuration: 所有頁面布局的合并持續(xù)時(shí)間
- RecalcStyleDuration: 所有頁面樣式重新計(jì)算的總持續(xù)時(shí)間
- ScriptDuration: JavaScript 執(zhí)行的持續(xù)時(shí)間
- TaskDuration: 瀏覽器執(zhí)行的所有任務(wù)的合并持續(xù)時(shí)間
- JSHeapUsedSize: 使用的 JavaScript 棧大小
- JSHeapTotalSize: JavaScript ??偞笮?/li>
2. Tracing。Tracing域可獲取頁面加載的 DevTools 性能跟蹤??梢允褂肨racing.start和Tracing.stop創(chuàng)建可在 Chrome DevTools 或時(shí)間軸查看器中打開的跟蹤文件。
我們能看到生成的 JSON 文件長這樣:
這樣的 JSON 文件,我們可以丟到 DevTools Timeline Viewer 中,可以看到對應(yīng)的時(shí)間軸和火焰圖:
3. Runtime。Runtime域通過遠(yuǎn)程評估和鏡像對象暴露 JavaScript 的運(yùn)行時(shí)??梢酝ㄟ^Runtime.getHeapUsage獲取 JavaScript 棧的使用情況,通過Runtime.evaluate計(jì)算全局對象的表達(dá)式,通過Runtime.queryObjects迭代 JavaScript 棧并查找具有給定原型的所有對象(可用于計(jì)算原型鏈中某處具有相同原型的所有對象,衡量 JavaScript 內(nèi)存泄漏)。
除了上面介紹的這些,還有Network可以分析網(wǎng)絡(luò)相關(guān)的性能,以及其他可能涉及 DOM 節(jié)點(diǎn)、JS 執(zhí)行等各種各樣的數(shù)據(jù)分析,更多的可能需要大家自己去研究了。
自動(dòng)化性能分析
通過使用 Chrome DevTools 協(xié)議,我們可以獲取 DevTools 提供的很多數(shù)據(jù),包括網(wǎng)絡(luò)數(shù)據(jù)、性能數(shù)據(jù)、運(yùn)行時(shí)數(shù)據(jù)。
對于如何使用該協(xié)議,其實(shí)已經(jīng)有很多大神針對這個(gè)協(xié)議封裝出不同語言的庫,包括 Node.js、Python、Java 等,可以根據(jù)需要在 awesome-chrome-devtools 這個(gè)項(xiàng)目中找到。
至于我們到底能拿到怎樣的數(shù)據(jù),可以做到怎樣的自動(dòng)化程度,就不在本文里講述啦,后面有機(jī)會(huì)再開篇文章詳細(xì)講講。
參考
- 你一定要知道的 Chrome DevTool 新功能
- 前端性能分析利器-Chrome 性能分析&性能監(jiān)視器
- 螞蟻金服如何把前端性能監(jiān)控做到極致?
- chrome devtools protocol——Web 性能自動(dòng)化實(shí)踐介紹
- Chrome DevTools Protocol
- Web Performance Recipes With Puppeteer