【QClient】ReactNative應(yīng)用自動化性能采集、分析和量化評估方案

背景

近幾年React Native技術(shù)棧的普及增速快,但其生態(tài)尚處于早期階段,在架構(gòu)、性能質(zhì)量、周邊設(shè)施上仍有很多優(yōu)化、填充和演進的空間。尤其在性能監(jiān)控評估方面以往針對原生、web的方式方法在React Native上不適用,目前Qunar大客戶端機票團隊已經(jīng)規(guī)模化使用React Native,在收獲跨平臺交付效率、快速迭代熱發(fā)布能力的同時我們希望能規(guī)范化應(yīng)用的性能水平,具備性能自動化監(jiān)控評估的APM設(shè)施。

解決什么問題

回到這個方案的初衷,是要解決這幾個方面的問題:

1.png

性能應(yīng)用水難以量化并導(dǎo)致調(diào)優(yōu)工作滯后

客戶端怎么樣算是性能好性能壞,在通常是沒有一個明確的界定方式的,事實上客戶端的性能調(diào)優(yōu)工作多數(shù)是被動滯后,開發(fā)階段大家用幾個手機點一點覺得流暢就是流暢,但其他真實用戶或是對體驗有較高要求的群體確實會有不一樣的感受結(jié)論。

RD對性能認知不足

即便生態(tài)發(fā)展迅速,React Native確實是一項非官方生態(tài)的新技術(shù),這個生態(tài)所積累的深度學習資源和最佳實踐經(jīng)驗不足夠豐富,部分開發(fā)者對其性能方面的認知還不足。

怎么辦 -- 設(shè)計目標與實現(xiàn)拆解

針對開發(fā)和項目過程痛點,我們期望的目標如下:

  • 項目性能評估客觀可量化
  • 自動化偵測性能缺陷
  • 問題定位輔助決策

方案拆解思路:首先是找到針對React Native的性能相關(guān)性數(shù)據(jù),也就是當性能出現(xiàn)下滑時,可以通過哪些維度的數(shù)據(jù)表現(xiàn)出來;然后有了數(shù)據(jù)樣本需要進行記錄;之后時對瞬時和一段周期內(nèi)的樣本進行自動化分析;最后時提供結(jié)果反饋。

2.png

解決方案

首先是性能相關(guān)性數(shù)據(jù)的實時采樣模塊,包括MRT(消息響應(yīng)及時性)、GCP(繪圖指令生效推遲)、邏輯同步幀率等。
其次是對樣本的記錄,記錄模塊目前支持兩種記錄模式,一種是存儲在手機本地,一種是提供外放協(xié)議可以把數(shù)據(jù)投遞到外部對接系統(tǒng)。
之后是實時分析,基于記錄的各個維度數(shù)據(jù)進行缺陷偵測并生成預(yù)警。通過輸出模塊輸出到開發(fā)者日志和可視化報表,這里我們后期有計劃自動生成對應(yīng)項目的性能bug對接到QA系統(tǒng)。

2.png

如何采集相關(guān)性數(shù)據(jù)、分析規(guī)則與調(diào)優(yōu)策略

在行業(yè)缺乏相關(guān)方案的背景下,最難地方在于尋找React Native應(yīng)用的性能相關(guān)性數(shù)據(jù)都是什么,在哪里,圍繞RN的實現(xiàn)原理我們挖掘到了這些維度:

  • MRT(消息相響應(yīng)及時性)
  • GCP(繪圖指令延遲)
  • 無SCU優(yōu)化、冗余render調(diào)用偵測
  • 繪圖幀率與邏輯同步幀率
  • 關(guān)鍵線程CPU負載
  • 內(nèi)存用量
  • 流量消耗
2.png

下面著重講解幾個代表性的性能相關(guān)性數(shù)據(jù)自動化采集分析和對應(yīng)的調(diào)優(yōu)策略

MRT(消息響應(yīng)及時性)

拋開具體實現(xiàn),React Native中Native域與JS域互操作的最簡化模型如下,兩邊各有一個基于消息隊列模型的線程,js側(cè)這個線程就是javascript代碼執(zhí)行的線程,native側(cè)是native_module_thread用來執(zhí)行js測投遞過來的NativeModule調(diào)用。兩側(cè)的互操作是基于jni向?qū)Ψ酵哆f消息,不同于大多數(shù)原生開發(fā)的單域僅是內(nèi)存地址對應(yīng)的代碼塊,因為涉及到線程切換、反射、任務(wù)隊列、雙向異步,這個過程并沒有那么及時,尤其涉及到視圖頻繁變更、手勢事件傳遞這些場景下相對原生方案延遲還是蠻大的。

圖片.png

MRT偵測、預(yù)警

我們的APM支持對這個指標進行實時采樣,并針對異常峰值進行自動化預(yù)警反饋。這樣RD在開發(fā)階段可以及時感知到諸“如按鈕點擊了onPress沒有調(diào)用“、“js函數(shù)執(zhí)行了但沒有在native上生效的“這些在過去比較隱蔽的性能缺陷。

圖片.png

MRT優(yōu)化策略

  • 減少native/js互操作頻次,比如移到單域處理(比如Animation的useNativeDriver的設(shè)計符合這一原則)
  • 減少native_module_thread任務(wù)堆積。比如提高算法效率、利用多核CPU設(shè)計并行計算算法、使用異步來優(yōu)化調(diào)用等待鏈
  • 減少js_thread上任務(wù)堆積。比如單線程模型上對大任務(wù)做拆解、優(yōu)化調(diào)度順序。
附React Native中Native與JS互操作原理圖
圖片.png

圖片.png

偵測無SCU優(yōu)化的組件和計算

SCU優(yōu)化(shouldComponentUpdate optimization)是在reactjs/react native中經(jīng)常強調(diào)的一個調(diào)優(yōu)項。我們通過hook組件的componentDidUpdate對先后的props和state做deepdiff,根據(jù)結(jié)果分為深比較值不等、深比較僅函數(shù)不等、淺比較為開發(fā)者提供優(yōu)化建議。在反饋報表中可以清晰感知到哪些組件發(fā)生了冗余的render以及優(yōu)化收益預(yù)估。

圖片.png

防止冗余render調(diào)用調(diào)優(yōu)策略

對于使用Redux管理數(shù)據(jù)事件流的項目
  • store使用不可變數(shù)據(jù)結(jié)構(gòu)
  • 根據(jù)組件需要的最小化依賴按需定制mapStateToProps
  • 使用PureComponent或redux connect、qrn-reduxPlugin賦予淺比較規(guī)則
  • 避免單個render函數(shù)/stateless function生成深度和廣度較大的JSX Tree
對于使用MobX的項目

MobX的自動化依賴收集機制在數(shù)據(jù)變更后會定向更新最小粒度的組件,且observer組件的SCU函數(shù)已經(jīng)被替換無需考慮SCU,非observer組件使用PureComponent并遵循性能編程規(guī)范即可。

渲染幀率與邏輯幀率

樣本采集
圖片.png

React Native的實際渲染執(zhí)行和視圖屬性計算聲明是彼此異步進行,以往針對原生應(yīng)用的幀率監(jiān)控指標在RN應(yīng)用下會非?!昂每础?,幾乎不可能出現(xiàn)ANR,極少會掉幀。但事實是js域的每次render執(zhí)行并不是實時生效到實際界面上,js域上的視圖數(shù)據(jù)計算和屬性配置成為瓶頸。以安卓為例我們通過VSYNC特性在每兩幀間檢查是否發(fā)生JSInstance.onBatchCompleted視圖操作事務(wù)提交以及是否期間完成了對BatchedOperation Queue的執(zhí)行來判定native上每次渲染是否真的生效了來自js域提交的視圖操作。

圖片.png
對應(yīng)的針對渲染幀率與邏輯幀率的自動化分析規(guī)則

持續(xù)性弱體驗偵測

  • 渲染幀率或邏輯幀率連續(xù)n次連續(xù)掉幀
  • 過去5s內(nèi)渲染幀率或邏輯幀率的P80分位數(shù)是否>30fps

潛在缺陷偵測:

  • 瞬時幀率異常偵測(渲染幀率和邏輯幀率)

執(zhí)行過程限時超標偵測

通常在設(shè)計上我們會對一些模塊的初始化、數(shù)據(jù)處理和計算的關(guān)鍵體驗環(huán)節(jié)設(shè)定執(zhí)行耗時的限制,通過構(gòu)建AOP樣式的decorator,對同步函數(shù)和基于Promise/async/await協(xié)程的異步函數(shù)進行trace并統(tǒng)計是否實際執(zhí)行耗時不符合設(shè)計要求的環(huán)節(jié)。

@tracePerf({ expectedTimeCost: 200, strict: true })
async function invokeHeavyThingsXXX() {
    const result = await hotdog.invoke(...);
    await parallel.compute(result);
}

其他周邊:CPU關(guān)鍵線程負載、內(nèi)存用量、應(yīng)用流量用量監(jiān)測

關(guān)鍵線程(JS線程、native_module線程、UI線程)的持續(xù)性高負載偵測
內(nèi)存用量:vm heap用量、native heap用量、低內(nèi)存預(yù)警
流量:流量消耗飆升偵測

目前Profiler支持的自動化分析預(yù)警規(guī)則總結(jié)

圖片.png

可視化輸出反饋

開發(fā)者可以實時觀測性能評估過程的各項指標表現(xiàn),并從中收集反饋信息和優(yōu)化建議指引,將性能缺陷的挖掘和調(diào)優(yōu)前置到開發(fā)和測試階段。


圖片.png

適用范圍、如何接入

適用于所有基于React Native及其衍生方案如QRN的應(yīng)用
只需配置依賴,SDK化使用

圖片.png

對APM未來的思考

  • 開放式架構(gòu):將流程、設(shè)計約定、基礎(chǔ)功能和算法抽離為輕便的APM Core,把具體的sampler和profiler和output作為其上的插件實現(xiàn)進行剝離,各業(yè)務(wù)線團隊和開發(fā)者根據(jù)自身需要定制、擴展性能維度和分析規(guī)則。
  • 功能延展:擴展Output模塊和應(yīng)用范圍,對性能評級標準化并對接QA流程。
  • 自身性能優(yōu)化:部分js代碼移交到native去實現(xiàn),降低APM本身對js域單線程的負載損耗。
圖片.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容