走近科学,探究阿里闲鱼团队通过数据提升Flutter体验的真相
背景
?
閑魚客戶端的flutter頁面已經服務上億級用戶,這個時候Flutter頁面的用戶體驗尤其重要,完善Flutter性能穩定性監控體系,可以及早發現線上性能問題,也可以作為用戶體驗提升的衡量標準。那么Flutter的性能到底如何?是否像官方宣傳的那么絲滑?Native的性能指標是否可以用來檢測Flutter頁面?下面給大家分享我們在實踐中總結出來的Flutter的性能穩定性監控方案。
目標
過度的丟幀從視覺上會出現卡頓現象,體現在用戶滑動操作不流暢;頁面加載耗時過長容易中斷操作流程;Flutter部分exception會導致發生異常代碼后面的邏輯沒有走到從而造成邏輯bug甚至白屏。這些問題很容易考驗用戶耐心,引起用戶反感。
所以我們制定以下三個指標作為線上Flutter性能穩定性標準:
最終目標是讓這些數據指標驅動Flutter用戶體驗升級。
頁面滑動流暢度
我們先大概了解下屏幕渲染流程:CPU先把UI對象轉變GPU可以識別的信息存儲進displaylist列表,GPU執行繪圖指令來執行displaylist,取出相應的圖元信息,進行柵格化渲染,顯示到屏幕上,這樣一個循環的過程實現屏幕刷新。
閑魚客戶端采用的Native、Flutter混合技術方案,Native頁面FPS監控采用集團高可用方案,Flutter頁面是否可以直接采用這套方案監控?
普遍的FPS檢測方案Android端采用的是Choreographer.FrameCallBack,IOS采用的是CADisplayLink注冊的回調,原理是類似的,在每次發出Vsync信號,并且CPU開始計算的時候執行到對應的回調,這個時候表示屏幕開始一次刷新,計算固定時間內屏幕渲染次數來得到fps。(這種方式只能檢測到CPU卡頓,對于GPU的卡頓是無法監控到的)。由于這兩種方法都是在主線程做檢測處理,而flutter的屏幕繪制是在UI TaskRunner中進行,真正的渲染操作是在GPU TaskRunner中,關于詳細的Flutter線程問題可以參考閑魚之前的文章:深入理解Flutter引擎線程模式。
這里我們得出結論:Native的FPS檢測方法并不適用于Flutter。
Flutter官方給我們提供了 Performance Overlay (具體參考 Flutter performance profiling) 作為檢測幀率工具,可否直接拿來用?
上圖顯示了Performance Overlay模式下的幀率統計,可以看到,Flutter分開計算GPU 和UI TaskRunner。UI Task Runner被Flutter Engine用于執行Dart root isolate代碼,GPU Task Runner被用于執行設備GPU的相關調用。通過對flutter engine源碼分析,UI frame time是執行window.onBeginFrame所花費的總時間。GPU frame time是處理CPU命令轉換為GPU命令并發送給GPU所花費的時間。
這種方式只能在debug和profile模式下開啟,沒有辦法作為線上版本的fps統計。但是我們可以通過這種方式獲得啟發,通過監聽Flutter頁面刷新回調方法handleBeginFrame()、handleDrawFrame()來計算實際FPS。
具體實現方式:
注冊WidgetsFlutterBinding監聽頁面刷新回調handleBeginFrame()、handleDrawFrame()
通過計算handleBeginFrame和handleDrawFrame之間的時間間隔計算幀率,主要流程如下圖:
效果
到這里,我們完成Flutter中頁面幀率的統計,這種方式統計的是UI TaskRunner中的CPU操作耗時,GPU操作在Flutter引擎內部實現,要修改引擎來監控完整的渲染耗時,我們目前大部分的場景沒有復雜到gpu卡頓,問題主要還是集中在CPU,所以說可以反應出大部分問題。從線上數據來看,release模式下Flutter的流暢度還是蠻不錯的,ios的主要頁面均值基本維持在50fps以上,android相對ios略低。這里需要注意的是幀率的均值fps在反復滑動過程中會有一個稀釋效果,導致一些卡頓問題沒有暴露出來,所以除了fps均值,需要綜合掉幀范圍、卡頓秒數、滑動時長等數據才能反應出頁面流暢度情況。
頁面加載時長
集團內部高可用方案統計Native頁面加載時長是通過容器初始化后開啟定時器在容器layout的時候檢查屏幕渲染程度,計算可見組件的屏幕覆蓋率,滿足條件水平>60%,垂直>80%以上認為滿足頁面填充程度,再檢查主線程心跳判斷是否加載完成
再來看看weex頁面加載流程和統計數據的定義
Weex的頁面刷新穩定定義:屏幕內view渲染完成且view樹穩定的時間
具體實現:當屏幕內發生view的add/rm操作時,認為是可交互點,記錄數據。直到沒有再發生為止。
在概念上Flutter和weex的首屏時長和可交互時長并不完全一致,Flutter之所以選擇從路由跳轉開始計算時長主要是因為這種計算方式更貼近用戶體驗,可以獲取更多的問題信息,比如路由跳轉的時長問題等。
Flutter的可交互時長end點采用的算法與native一致,可見組件滿足頁面填充程度并且完成心跳檢查的情況下任務可交互,另外對于一些比較空的頁面,組件面積小,無法達到水平>60%,垂直>80%的條件,就用交互前最后一次Frame刷新時間點作為end點。
具體流程如下圖:
效果
由于debug模式采用的JIT編譯,debug模式下體驗加載時長偏長,但是release模式下的AOT編譯時長明顯縮短很多,整體頁面加載時長還是要優于weex。
Exception率
Flutter部分exception/error 會導致代碼后面的邏輯沒有走到造成頁面或邏輯bug,所以flutter的exception需要作為穩定性的標準之一
定義
FlutterException率 = exception發生次數 / flutter頁面PV
分子:exception發生次數(已過濾掉白名單)
Flutter內部assert、try-catch和一些異常邏輯的地方會統一調用FlutterError.
通過重定向FlutterError.到自己的方法中監測exception發生次數,并上報exception信息
分母:flutter頁面PV
具體實現如下:
其中,FlutterError.只會捕獲Flutter framework層的error和exception,官方建議將這個方法按照自己的exception捕獲上報需求定制。在實踐過程中,我們遇到很多不會對用戶體驗產生任何影響的exception會被頻繁觸發,這類沒有改善意義的exception可以添加白名單過濾上報。
效果
有了線上exception的監控,可以及早發現隱患,獲取問題堆棧信息,方便定位bug,提示整體穩定性
總結
到這里,我們完成Flutter頁面滑動流暢度、頁面加載時長和Exception率的統計,對于Flutter的性能有一個具體的數字化標準,對以后的用戶體驗提升和性能問題排查提供基礎。目前閑魚客戶端的商品詳情頁和主發布頁已經全量Flutter化,感興趣的同學可以體驗下這兩個頁面和其他頁面的性能差異,最后歡迎大家提供反饋和建議。
-----------------------------------------
本文作者:閑魚技術-三蒞
總結
以上是生活随笔為你收集整理的走近科学,探究阿里闲鱼团队通过数据提升Flutter体验的真相的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis 5.0新功能介绍
- 下一篇: 阿里云:面向5G时代的物联网无线连接服务