支付寶螞蟻金服是怎麼把前端性能監控作到極致的?

本文來自螞蟻金服前端技術專家楊森在 ArchSummit 北京 2018 的分享,他將分享如何經過 Performance 相關的 API 準確的採集用戶性能數據,並如何經過大數據計算加工最終產出用戶性能分析產品,以及如何經過性能數據縱向衡量產品性能、發現性能瓶頸。 本文的主要從如下四個方面闡述: 前端性能監控的兩種主要技術方案; 怎麼樣去作一個真實用戶性能數據的採集; 怎麼去分析這些數據; 這些性能數據在螞蟻金服怎麼應用。 前端性能監控的兩架馬車 從技術方面來說,前端性能監控主要分爲兩種方式,一種叫作合成監控(Synthetic Monitoring,SYN),另外一種是真實用戶監控(Real User Monitoring,RUM)。 合成監控 什麼叫合成監控?就是在一個模擬場景裏,去提交一個須要作性能審計的頁面,經過一系列的工具、規則去運行你的頁面,提取一些性能指標,得出一個審計報告。 合成監控中最近比較流行的是 Google 的 Lighthouse,下面咱們就以 Lighthouse 爲例。前端

Google Lighthouse 系統架構圖 Lighthouse 提供了不少種方案,可是咱們這裏演示的是一種以命令行工具的形式去對一個淘寶首頁作性能審計。咱們能夠輸出目標頁面,它就會在咱們這個模擬環境裏面打開淘寶,而後去作一些性能數據的提取。程序員

咱們會看到一個生成的性能報告,從這個性能報告裏咱們能夠看到,Lighthouse 生成的不只僅是一些性能相關的數據,甚至包括 PWA,而後一些 SEO,甚至一些前端工程化的最佳實踐等等。 固然其實業界對於 Lighthouse 也是評價有褒有貶,由於 Google 藉助這個看似中立的性能評審工具也是在推行它的一些技術的方案。 合成監控的優缺點 如今,咱們經過下表,來看看合成監控的優缺點:web

真實⽤用戶監控(RUM)算法

所謂真實用戶監控,就是用戶在咱們的頁面上訪問,訪問以後就會產生各類各樣的性能指標,咱們在用戶訪問結束的時候,把這些性能指標上傳到咱們的日誌服務器上,進行數據的提取清洗加工,最後在咱們的監控平臺上進行展現的一個過程。 真實用戶監控 (RUM) 的優缺點canvas

由於真實用戶監控也是在運行時執行,因此這種真實用戶監控比較難採集到一些硬件相關的指標,包括也很難去採集這個頁面執行的幻燈片(即逐幀截圖)。固然技術上,你能夠用 JS 把當前頁面保存成一個 Canvas,作一些逐幀對比,甚至把這些數據回傳回去。可是在實踐過程當中,咱們確定不會這樣作,由於這對用戶的流量是極大的浪費。介紹完這兩種監控方案咱們來看一下他們兩種方案的對比。前端工程化

下文中,咱們會着重介紹真實用戶性能數據採集的方案。 真實用戶性能數據採集方案 我認爲,在真實用戶性能數據採集時,要關注四個方面的東西: 使用標準的 API; 定義合適的指標; 採集正確的數據; 上報關聯的維度。 下面咱們來逐個解析一下。 使用標準的 API 若是你們有研究過前端性能監控,可能會知道瀏覽器會提供這麼一個 API 叫 performance.timing,它會提供一個頁面,從開始加載一直到加載完畢,中間各個階段的一個模型,但這個 API 已經「廢棄」了。爲何會被廢棄?由於 W3C 給咱們提供了更全面、更強大的一個性能分析矩陣,比單一的 performance.timing 更增強大,能幫助咱們從各個方面分析前端頁面性能。瀏覽器

還有 High Resolution Time 這個基礎的 API,能夠爲咱們提供更精準的 timestamp。緩存

爲何全部的這些規範都是基於這個高精度時間的規範呢。你們寫過 JS 都知道,能夠用 Data.API 去提取當前的時間軸,單位是毫秒,這是咱們新的高精度時間的定義,它能夠經過 performance.now 來獲取,它的單位也是毫秒。可是一樣是毫秒, performance.now 返回的變量小數點後面 10 位以上是有的,這裏面我列了一個簡單的轉換式,你們能夠換算一下,是能夠精確調納秒級別的。這就是高精度時間的第一個特性。 爲何叫高精度時間,就是精度很是之高,也是爲了適應如今前端一些複雜的一些性能衡量的場景,包括一些複雜的動畫場景,須要的一些高精度的定義。 那麼 High Resolution Time 的另一個特性就是,當咱們在用戶界面獲取當前時間,而後修改一下系統時間,再次調用同一個方法就能夠獲取當前時間。服務器

爲了方便你們去對比,我列了一個輔助線,能夠看到,一樣是調用 Data.now 這個 API 獲取系統時間,若是咱們修改了系統時間,在獲取時間的時候,咱們拿到的是,就是當前對應的系統時間。好比說咱們先獲取一次,修改系統時間再獲取一次,Data.now 就變成了昨天的時間,可是與此同時,HR.time 實際上是不會受這個系統時間變動的影響的,它依然會單調的遞增,這個是 HRtime 的第二個特性,它是一個單調遞增的。 因此綜合來講,HRtime 有兩個特性,一個高精度,一個單調遞增,保證了咱們在提取性能指標的時候,不會受宿主環境的一些時間影響。 而後在 HRTime 之上,是一個叫 PerformanceTimeline 的 API,這個 API 很簡單,它只是去定義了把各類各樣的性能的狀況。 在此,咱們得出的最佳實踐是:採集性能數據時先抹平 Navigation Timing spec 差別,優先使用 PerformanceTimeline API(在複雜場景,亦可考慮優先使用 PerformanceObserver)。 定義合適的指標 講完使用標準的 API,咱們來看一看,怎麼定義合適的指標,假設有一天你老闆問你說,咱們頁面性能怎麼樣,你回答他,反正我以爲打開挺快的,這是一個很是不嚴謹的論述。咱們到底怎麼樣定義咱們的頁面性能呢,其實業界有很是多的方案,這裏只是列舉了十幾個相對來講比較常見的一些的性能指標定義方式。網絡

那麼在這麼多方案裏邊,到底哪些指標是適合咱們的,我挑了幾個具備典型表明意義的指標例子,給你們作個詳細的講解。 首先咱們來看一看你們最熟悉的頁面加載時長,頁面加載時長是被清晰的標在這個頁面的底部的。它是指 DOM load 事件觸發完成,它的優勢有: 原生 API; 接受度高; 感知明顯(瀏覽器 Tab 中止 loading)。 缺點是: 沒法準確反映頁面加載性能; 易受特殊狀況影響。 爲了解決這個問題,W3C 的工做小組引入了首次渲染 / 首次內容渲染。首次渲染是指第⼀個非網頁背景像素渲染,⾸次內容渲染是指第一個⽂本、圖像、背景圖片或非白色 canvas/SVG 渲染。 這裏以打開 YouTube 爲例,由於打開這個網站可能相對反應會慢一點,咱們能更容易發現這種區別。當你去採集這兩個指標的時候,你會發現,或者說你在大部分時候會發現,這兩個指標沒有任何差別。 根據咱們實際採集到的性能數據也證明了咱們的觀點,在 70% 的狀況下,First Paint 和 First Contentful Paint 他們兩個指標之間的差別小於一百毫秒,爲何?由於如今一個前端網站的架構設計是傾向於單頁應用的,它本來的 HTML 結構很是小巧。在渲染的時候,尤爲是在第一次渲染的時候,它就已經可以把文本和背景一塊兒渲染出來了,這兩個指標差別會很是之小。 咱們能夠總結一下,這兩個指標相比於頁面加載時長它更聚焦於頁面元素的渲染,相對來講更客觀,但同時能夠看到,頁面上有象素被渲染出來,並不必定表明着用戶去看到了它關心的主要內容,在實際的經驗中也能夠看到,大多數時候,這兩個指標的相差並非特別大。 那麼頁面加載時長會有異常狀況,First Paint 和 First Contentful Paint 又會有各類差別不大,或者是不可以徹底表明這個頁面性能的狀況,因而就有下面一個算法,經過算法計算出來的指標,叫作 First Meaningful Paint,首次有效渲染時長,這個指標最先是由 Google 提出的,它的一個核心的想法是渲染並不必定表明着用戶看到了主要內容,Load 也不必定表明用戶看到主要內容,那用戶何時可以看到主要內容呢?咱們假設當一個網頁的 DOM 結構發生劇烈的變化的時候,就是這個網頁主要內容出現的時候,那麼在這樣的一個時間點上,就是用戶看到主要內容的一個時間點。 它的優勢是相對校準的估算出內容渲染時間,貼近用戶感知。但缺點是無原生 API 支持,算法推導時 DOM 節點不含權重。 而後最後一種指標叫作開始渲染時間,Start Render Time,這個指標時間是沒有辦法或者很難經過 JS 在用戶環境執行來獲取的。由於它的定義很是簡單,就是假設咱們開始加載頁面,一直拿個照相機對着屏幕拍,直到拍到有一幀,發現這個頁面不同了,那麼這個時間就是頁面的一個開始渲染時間。這個定義看起來和那個剛纔講的一個 First Paint 很是像,但實際上,由於它的採集方式不同,First Paint 仍是經過瀏覽器的渲染引擎來計算出來的時間,而 Start Render Time 就是客觀觀察到頁面的一個加載變化的時間,因此可能 Start Render Time 可以更客觀地反映咱們頁面的加載狀況,可是由於這個指標很難經過 JS 計算,因此是僅僅做爲一個參考。 講了這麼多性能指標的定義方法,咱們作一個簡單的總結。

這麼多的性能指標,咱們到底應該怎麼選呢?咱們得出了最佳實踐:根據業務特性及性能監控方案選擇最適合的性能指標,必要狀況下可以使用自定義性能點位。 怎樣採集正確的數據? 定義完合適的指標,咱們來看看怎麼樣採集正確的數據。 不同階段之間是連續的嗎?

這是目前最規範的一個 RUM 性能模型,能夠看到咱們的頁面加載被定義成了不少個階段。 不少作性能監控的方案都是計算階段再上報數據,固然這能夠減小數據傳輸量,可是在實際的應用中咱們會發現,這樣作是有問題的。 好比說 DNS 查詢完,立刻就開始創建 TCP 鏈接了嗎?TCP 連 接完立刻就開始去發送這個請求了嗎?其實是不必定的,除了咱們剛纔模型定義的階段以外,會有一個叫作 stalled 的時間,那麼這個階段發生了什麼事情呢?

當你觀察到有這種 blocked 或者 stalled 的時間出現的時候,大部分狀況下,都是由於被同域名 TCP 併發鏈接限制了,就好比說,咱們一個頁面可能加載了 CDN 上的十個資源,那麼在 TCP 鏈接會有限制,好比 Chrome 它就會有限制。單頁面、單個域名的 TCP 鏈接,併發數是 6,也就是說加載十個資源,只有六個鏈接被真正創建了,剩下四個資源是要等待這六個鏈接消費完成以後才能被複用的。 還有其餘的一些狀況也會致使這個頁面 stalled 的時間產生,若是咱們只是用剛纔那個性能去計算某一個階段的時間的話,就會把這個 stalled 的時間漏掉,這樣會致使咱們真正把各個階段加起來去算這個頁面總的加載時間的時候,出現一個偏差。在實際觀察中咱們會發現,這種 stalled 時間是很是常見的。 每一個階段都必定會發生嗎?

一個最典型的例子,DNS 查詢,每次頁面訪問都會去查 DNS 嗎?咱們知道如今瀏覽器會對 DNS 查詢結構作緩存了,你第一次訪問了淘寶,你第二次再訪問的時候,很大機率 DNS 是不會再查詢了的,那麼這個階段可能算出來就是 0,那麼在各類特殊的狀況下,咱們怎樣去採集這個正確的數據呢? 咱們目前得出的結論是:上報頁⾯加載開始時間,以及後續各時間點相對增量,在數據端進行階段清洗和異常處理。 好比說頁面開始加載時間是 0 秒,那麼從 0 項開始時間是一毫秒,TCP 開始時間是兩毫秒,把各個時間點相對的增量算出來。 最後在數據端進行一個階段的清洗,以及異常的處理,這樣一方面可以保證在規範定義中沒有被體現出來的階段不會被遺漏掉,另外一方面也可以讓咱們去掌控這個頁面加載的分佈究竟是怎樣的,也不會由於咱們在前端就把這個頁面算好,遺漏致使數據的丟失。 採集完合適的指標,最後一個是上報關聯的維度。

咱們都知道在作前端的數據採集的時候,維度數據是很是重要的,除了咱們剛纔定義的各類度量,怎樣採集到合適的相關維度,也可以極大地幫助咱們分析頁面性能的效果。 上圖提到的點都是必需要採集的,可是在分析頁面性能的時候,有不少相對專業的維度是會被你們忽略掉的,好比說當前頁面是否可見,這個頁面加載方式是怎麼樣的,它是直接打開,仍是刷新打開,仍是前進後退打開等等。就是經過後面的數據分析,咱們會發現,不一樣的頁面操做,頁面打開方式都會對咱們頁面加載的性能會有影響,以及一些更復雜的,好比說是否啓用 HTTP二、Service Worker 等等,這些數據咱們都應該儘量採集到,從而可以更好的去分析咱們的頁面性能。 準確分析性能數據及影響因素 講完前端數據的一些採集,咱們來看一看怎麼樣去分析這些性能數據。這個是咱們採集到真實的螞蟻的某一個業務的頁面加載時長數據。能夠看到大部分的頁面都會在 10 秒內完成這個頁面的加載,可是仔細觀察就會發現,還會有大量的長尾值存在,能夠看到從 10 秒到 30 秒,甚至到 60 秒,都會採集到這樣的數據,這也是一個很是真實的狀況。

這個數據能夠從兩個方面進行解讀,第一,因爲頁面加載時長會受不少異常因素的影響,你的用戶可能已經在正常地使用你的網站業務,只不過一個 icon 沒加載出來,一個小圖片沒加載出來,就會致使這個指標變得超長,這都是合理的狀況。而另一種狀況就是在分析性能數據的時候,咱們會發現,長尾的數據是很是常見的,由於影響外部性能因素太多了,除了前端本身的緣由,除了咱們 JS 寫的太大,靜態資源太多,沒有壓縮等等,好比用戶的網絡很差,服務器壓力忽然很高,甚至 IO 堵塞了,均可能致使最後這個頁面沒有被渲染出來。 在螞蟻內部,咱們開玩笑說,一些體量比較小的業務,可能有一天它的用戶蹲在廁所裏面用手機去刷了一下它的網站,頁面加載時長統計出來的數據就要暴漲,這都是很是真實可能存在的狀況。 咱們理解這些長尾數據以後,來看一看還會有哪些影響咱們這個頁面加載性能的因素,我剛纔在那個上報維度裏面講到了,頁面的可見狀態是一個很是大的影響因素,從 Chrome 68 開始,Chrome 啓用了一種全新的瀏覽器的架構模式,在這種模式下,其實它對不可見 Tab 的硬件資源的分配作了一個極大的限制。 你會發現,在你的不可見 Tab 下,可能你的動畫會被減慢。那麼好比說用戶他在後臺打開你的頁面,就是說它在前一個頁面,好比說右鍵,先打開,後面右鍵後臺先打開,這個時候在你這個新打開的頁面去提取性能數據的時候,會發現那個性能就沒有正常打開,相對來講就沒有那麼好。 另一種頁面加載方式也會影響咱們頁面性能,好比咱們正常打開一個頁面會去加載各類各樣的資源,若是刷新打開,可能有一些緩存,瀏覽器幫咱們作掉了,一些靜態資源,304 沒有更新,遊覽器就不會從新下載,好比說前進後退的時候,甚至瀏覽器會幫咱們作一些頁面內容的緩存,有些頁面前進後退都是秒出的,根本沒有出現那種頁面完整刷新的效果,就是這種不一樣的頁面加載方式,會影響到咱們頁面的性能數據的採集結果。 最後一種就是 Service Worker,你們若是實踐過就會發現,Service Worker 能力很是強大,它能夠作很是強大的緩存,這是可能會影響到整個頁面的一個性能。 數據是如何撒謊的? 最後一個我想講的是,咱們性能數據是怎麼樣撒謊的,仍是以剛纔這個採集到的性能直方圖爲例,老闆問說,你性能採集到了,你給我一個數,大家這個頁面性能到底怎麼樣?我說我算了一下,大概是 6 秒左右。

「我本身是一名從事了5年前端的老程序員,辭職目前在作講師,今年年初我花了一個月整理了一份最適合2019年學習的web前端乾貨,從最基礎的HTML+CSS+JS到移動端HTML5到各類框架都有整理,送給每一位前端小夥伴,這裏是小白彙集地,歡迎初學和進階中的小夥伴。"

加QQ羣:931661106(招募中)

關注公衆號:蝌蚪前端

老闆不開心了,說這個數據怎麼這麼大?而後咱們能夠經過一些小技巧,一些不一樣的加工方式,又算了一下,算出來是 4.2 秒左右,老闆說還能夠再好一點。又換一種加工方式,2 秒 5 左右,這個數字不錯,一樣的一份數據,原始的直方圖就擺在這裏,一樣的一份數據,爲何會得出三個大相徑庭的結論呢? 這是由於咱們指標計算的口徑不同,第一個數據,特別大的數據是 95 分位數,所謂 95 分位數就是把咱們全部的頁面加載時長,從小到大排列,取第 95% 的位置,這個值做爲咱們的性能指標,那麼使用 95 分位數,隱含的意義就是,咱們承諾 95% 的人訪問咱們頁面的時候,頁面加載時長是小於 6 秒的。後面一種雞賊的方法就是咱們取平均數,緩存特別好的,可能幾十毫秒就打開了,緩存很差的幾十秒纔打開,咱們取平均一下,看起來也很中立,4 秒多;若是咱們再雞賊一點,好比說咱們長尾數據特別長,咱們還能夠取 10% 的截尾平均數,掐頭去尾取平均,這樣的數據看起來就很是漂亮。 可是在實際上,若是咱們作的是一個給本身看的性能產品,咱們應該是對本身的性能數據負責任,因此,在實際分析性能指標的時候,咱們是建議分析性能指標時建議關注百分位數 (percentile),對性能的要求越高,使用越大的百分位數。 好比咱們要承諾 99% 的用戶都要小於 5 秒,咱們看頁面加載時長時候就應該看 99 分位數。若是咱們如今精力不夠,咱們只能承諾 50% 的人頁面加載時長小於 5 秒,實際上 50 分位數,就是中位數,就是 50% 的訪問可以不小於這個時間打開這個頁面。 總結 最後一點,我想講的是在螞蟻金服,咱們是怎麼用這些性能數據的。 首先性能數據採集固然是要給用戶一個分析的結果,由於這是一個性能分析的產品,咱們要從各類維度,各類時間和剛纔講到的關聯的維度,給用戶一個分析的抓手,告訴它你的性能瓶頸在哪裏,你的綜合的狀況怎麼樣的,讓用戶感知他的業務究竟是快仍是慢。 一些客觀的數據可以瞭解本身業務的綜合狀況,可是看到本身的數據還不夠,咱們在螞蟻金服在作另一件事情,就是對全部中後臺產品作一個性能數據的橫向比分,固然不只僅是性能數據,這個產品是綜合的一個叫體驗分的東西,體驗包括了性能數據,同時也包括了頁面的美觀度,用戶的感知度,以及一些任務的轉化率等等,其中這個性能的分數能夠經過咱們採集到的性能的指標來反饋。而後固然你的可能有人就會以爲說,咱們業務形態不同,咱們的前端架構方式不同,你把這些分數橫向比較有什麼意義?

每晚7點直播講課,送前端學習資料,從基礎到框架,專業的老師爲你指導

加微❤:QD_666_QD

這個時候就涉及到性能指標的定義,應該儘量的選取對,若是咱們是一個性能監控的中臺,而不是一個簡單的對本身業務性能的一個監控,咱們應該儘量的選取一箇中立的指標去衡量,就是客觀的衡量各類業務的一個展現形態,同時在作一個橫向比較的時候,咱們也會換用不一樣的性能計算方式,好比說在這個體驗分項目裏面,咱們就會用截尾平均值,目的並非爲了讓這個數據變得好看,是爲了讓這個數據變得平穩,讓異常值不會產生太大的影響。同時咱們在一些橫向比較中,或者在這種大盤的比較項目中,咱們也會盡量的去讓用戶關注自身性能的一個提高,你能夠不關心你比別人快仍是慢,可是你要關心你比以前快了仍是慢了。

以上就是整個性能數據的分享以及在螞蟻金服的應用,謝謝你們。

相關文章
相關標籤/搜索