<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          有贊移動(dòng)性能監(jiān)控平臺(tái)(一)

          共 6778字,需瀏覽 14分鐘

           ·

          2021-02-25 21:25

          前言

          隨著移動(dòng)端業(yè)務(wù)復(fù)雜度的提升,開(kāi)發(fā)同學(xué)在編寫(xiě)業(yè)務(wù)的時(shí)候往往容易忽略性能問(wèn)題,雖然有贊移動(dòng)端自研了 APM ,但是 APM 采集的都是線上的數(shù)據(jù),無(wú)法在 QA 與開(kāi)發(fā)階段提前發(fā)現(xiàn)問(wèn)題,為了保障軟件的穩(wěn)定性,需要補(bǔ)齊線下監(jiān)控能力,避免性能問(wèn)題上線對(duì)商家經(jīng)營(yíng)過(guò)程造成影響。

          一、架構(gòu)設(shè)計(jì)

          整體基于 APM 現(xiàn)有框架迭代線下監(jiān)控能力,并在端上開(kāi)發(fā) AWACS 可視化工具,通過(guò)全局懸浮窗,并結(jié)合提醒能力(彈窗與 Toast 提示)實(shí)時(shí)通知測(cè)試人員進(jìn)行問(wèn)題查看,同時(shí)后臺(tái)也會(huì)定時(shí)分析測(cè)試環(huán)境采集的性能數(shù)據(jù),進(jìn)行管理與分配。

          QA 同學(xué)基于 Appium 補(bǔ)齊了 UI 主流程 case ,通過(guò)自動(dòng)化測(cè)試最大程度確保每次應(yīng)用發(fā)版的穩(wěn)定。而設(shè)備自動(dòng)化回歸流程可以與線下監(jiān)控完美的結(jié)合起來(lái),首先每個(gè)版本可以確保運(yùn)行在同一款設(shè)備上,其次每個(gè)版本運(yùn)行的主流程用例基本上保持一致,這樣就為應(yīng)用“前后”版本性能數(shù)據(jù)分析對(duì)比提供了兩個(gè)參照條件。性能問(wèn)題上報(bào)后,除了微信Robot通知相關(guān)干系人解決問(wèn)題外,還基于移動(dòng)端 mPaaS 搭建了問(wèn)題管理與分配平臺(tái),便于跟進(jìn)與追蹤。

          二、監(jiān)控指標(biāo)分析

          性能監(jiān)控目前對(duì)階段、流量、頁(yè)面耗時(shí)、 ANR 、慢方法、 fps 等數(shù)據(jù)做了實(shí)時(shí)監(jiān)控,本篇文章只會(huì)對(duì)階段、流量、頁(yè)面耗時(shí)進(jìn)行歸納分析,后面“有贊移動(dòng)性能監(jiān)控平臺(tái)系列文章“會(huì)對(duì) ANR 、慢方法、 fps 等監(jiān)控?cái)?shù)據(jù)進(jìn)行總結(jié)。

          2.1 階段數(shù)據(jù)

          移動(dòng)端每個(gè)業(yè)務(wù)流程都可以統(tǒng)稱為“階段”,比如 App 啟動(dòng)、商品加購(gòu)、商品查詢等,業(yè)務(wù)方可以對(duì)自身需要關(guān)心的業(yè)務(wù)階段進(jìn)行監(jiān)控,結(jié)合“數(shù)據(jù)分析”與“告警能力”快速協(xié)助業(yè)務(wù)方排查問(wèn)題。階段分析包括“方法耗時(shí)分析”與“網(wǎng)絡(luò)狀況分析”兩個(gè)部分,下面會(huì)具體介紹。

          2.1.1 方法耗時(shí)分析

          在 App 編譯期會(huì)對(duì)每個(gè)方法進(jìn)行前后打點(diǎn),確保運(yùn)行過(guò)程中每個(gè)階段方法耗時(shí)都可以被自動(dòng)統(tǒng)計(jì)出來(lái),節(jié)省手動(dòng)打點(diǎn)統(tǒng)計(jì)成本。
          原理
          開(kāi)發(fā) Gradle Plugin 插件,在 App 編譯 Transform 階段( .class 轉(zhuǎn)換為 .dex 過(guò)程),對(duì)字節(jié)碼進(jìn)行操作,在方法的開(kāi)始執(zhí)行( methodEnter )與結(jié)束執(zhí)行( methodExit )通過(guò) ASM 工具分別插入 MethodBeat 的 i 與 o 方法,對(duì)每個(gè)方法進(jìn)行首尾打點(diǎn),運(yùn)行時(shí)自動(dòng)統(tǒng)計(jì)方法耗時(shí)。
          分析詳情
          應(yīng)用所有版本產(chǎn)生的階段數(shù)據(jù)都會(huì)上傳到后端,后端會(huì)通過(guò)定式任務(wù)對(duì)階段數(shù)據(jù)進(jìn)行分析,分析角度分為新增、新減、陡增、陡降4個(gè)維度,協(xié)助開(kāi)發(fā)綜合對(duì)問(wèn)題進(jìn)行排查。啟動(dòng)階段舉例:

          2.1.2 網(wǎng)絡(luò)狀況分析

          業(yè)務(wù)方可以定義是否需要監(jiān)控階段的網(wǎng)絡(luò)狀況,比如啟動(dòng)階段,除了要監(jiān)控啟動(dòng)方法耗時(shí)之外,網(wǎng)絡(luò)狀態(tài)也需要進(jìn)行監(jiān)控( App 啟動(dòng)時(shí),硬件負(fù)載比較高,過(guò)多的網(wǎng)絡(luò) IO 請(qǐng)求會(huì)拖累啟動(dòng)速度)。
          原理
          有贊零售 App 網(wǎng)絡(luò)通過(guò) OkHttp 進(jìn)行請(qǐng)求,通過(guò)自定義攔截器對(duì)網(wǎng)絡(luò)進(jìn)行統(tǒng)一攔截,統(tǒng)計(jì)每個(gè)階段網(wǎng)絡(luò)鏈接數(shù)量與請(qǐng)求耗時(shí), intercept 方法實(shí)現(xiàn)如下:
          public Response intercept(Chain chain) throws IOException {        Request request = chain.request();        Response response = null;        String url = getRequestUrl(request.url());        if (!TextUtils.isEmpty(url)) {            AppSegmentCache.INSTANCE.setRequestStart(url);            long startNs = System.nanoTime();            try {                response = chain.proceed(request);            } catch (Exception e) {                throw e;            }            long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);            AppSegmentCache.INSTANCE.setRequestEnd(url, tookMs);        }        return chain.proceed(request);    }
          分析詳情
          分為“全部調(diào)用”與"重復(fù)調(diào)用"兩個(gè)統(tǒng)計(jì)維度,“全部調(diào)用”會(huì)統(tǒng)計(jì)當(dāng)前版本該階段網(wǎng)絡(luò)請(qǐng)求總數(shù),且會(huì)與上個(gè)版本請(qǐng)求總數(shù)進(jìn)行比較,計(jì)算出升降趨勢(shì)(提升/下降了 x%),且列出“新增”與“新減”兩個(gè)數(shù)據(jù)維度,協(xié)助對(duì)網(wǎng)絡(luò)狀況進(jìn)行分析?!爸貜?fù)調(diào)用”會(huì)統(tǒng)計(jì)所有重復(fù)調(diào)用的接口狀況,包括網(wǎng)絡(luò)重復(fù)請(qǐng)求的總數(shù),還會(huì)全部列出重復(fù)調(diào)用鏈接內(nèi)容,方便業(yè)務(wù)方進(jìn)行排查優(yōu)化。

          2.2 流量

          App 運(yùn)行過(guò)程中主要涉及到接口、文本、視頻、圖片等各種流量請(qǐng)求,往往在開(kāi)發(fā)過(guò)程中不太會(huì)注意流量消耗這個(gè)指標(biāo),最近也經(jīng)常有商家反饋 App 流量消耗比較大,但目前并不能準(zhǔn)確的定位流量消耗主因。

          2.2.1 原理

          分別對(duì) HttpUrlConnection 和 OkHttp 做 Hook ( .class -> .dex transform 流程插樁),所有的請(qǐng)求都得經(jīng)過(guò) Hook 層,這樣就能統(tǒng)計(jì)每個(gè)請(qǐng)求的流量大小與 response 內(nèi)容,便于業(yè)務(wù)方進(jìn)行分析。
          OkHttpHook
          App 編譯期往 OkHttp 中配置 GlobalNetworkInterceptor 攔截器,統(tǒng)計(jì) response length(流量大小)、response content(請(qǐng)求返回內(nèi)容,如果是 gzip 需要解壓),然后將流量?jī)?nèi)容寫(xiě)入文件中(非線上包才會(huì)采集),便于分析。
          internal object OkHttpHook {    @JvmField    public val globalNetworkInterceptor = Interceptor { chain ->    ... ...    // 計(jì)算repsonse length(流量大?。?/span>    // 讀取response content(如果是gzip需要解壓)    // 流量?jī)?nèi)容寫(xiě)入文件中    val fileUrl = File(file, URLEncoder.encode(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss-SSS").format(Date()) + "-" + netPackInfo.url))    fileUrl.writeText(netPackInfo.toString())    ... ...}
          HttpUrlConnectHook
          編譯期對(duì) HttpUrlConnection 進(jìn)行 Hook ,底層網(wǎng)絡(luò)請(qǐng)求其實(shí)是代理到 OkhttpClient 上,這樣就能保證 HttpUrlConnection 所有網(wǎng)絡(luò)請(qǐng)求也能通過(guò) OkHttp 進(jìn)行處理,這樣流量攔截器( GlobalNetworkInterceptor )就可以進(jìn)行復(fù)用了。
          public object HttpUrlConnectHook {    @JvmStatic    fun proxy(httpUrlConnection: URLConnection): URLConnection {        try {            return hookOkHttpURLConnection(httpUrlConnection)        } catch (e: Exception) {            e.printStackTrace()        }        return urlConnection    }}
          @Throws(Exception::class)private fun hookOkHttpURLConnection(httpUrlConnection: URLConnection): URLConnection { val builder = OkHttpClient.Builder() val mClient = builder .retryOnConnectionFailure(true ... ... .build() val strUrl = httpUrlConnection.url.toString() val url = URL(strUrl) val protocol = url.protocol.toLowerCase(Locale.ROOT) if (protocol.startWith("http", ignoreCase = true)) { return HttpUrlFactory.OkHttpURLConnection(url, mClient) } else urlConnection}

          2.2.2 分析詳情

          通過(guò)展示網(wǎng)絡(luò)各個(gè)統(tǒng)計(jì)指標(biāo)數(shù)據(jù)詳情,包括每個(gè)接口的請(qǐng)求流量大小、請(qǐng)求次數(shù)、請(qǐng)求內(nèi)容,便于技術(shù)人員對(duì)流量問(wèn)題進(jìn)行分析。

          2.3 頁(yè)面耗時(shí)

          有贊零售面向B端的產(chǎn)品,適配了很多低端收銀機(jī),在頁(yè)面流暢性有嚴(yán)格要求,通過(guò)頁(yè)面耗時(shí)監(jiān)控,統(tǒng)計(jì)每個(gè)頁(yè)面( Activity | Fragment )的耗時(shí),當(dāng)頁(yè)面耗時(shí)超過(guò)閾值時(shí),會(huì)生成問(wèn)題,分配給相應(yīng)的處理人進(jìn)行修復(fù)。

          2.3.1 原理

          監(jiān)控 Activity 與 Fragment onCreate() 方法開(kāi)始執(zhí)行作為頁(yè)面繪制開(kāi)始時(shí)機(jī),頁(yè)面 onDraw() 方法第一次回調(diào)時(shí)機(jī)作為頁(yè)面繪制結(jié)束時(shí)機(jī),兩個(gè)時(shí)機(jī)做減法,算出頁(yè)面渲染耗時(shí)。
          頁(yè)面監(jiān)控開(kāi)始時(shí)機(jī)
          在 ActivityLifecycleCallbacks 全局監(jiān)聽(tīng) Activity 生命周期,在 onActivityCreated() 方法中調(diào)用 watchActivity() 方法,watchActivity 除了統(tǒng)一對(duì) Activity 頁(yè)面預(yù)埋開(kāi)始時(shí)機(jī)外,還會(huì)區(qū)分 Activity 類(lèi)型,對(duì) Activity 內(nèi)嵌的 Fragment 注冊(cè) FragmentLifecycleCallbacks 監(jiān)聽(tīng),同樣在 onFragmentViewCreate() 回調(diào)中對(duì)Fragment頁(yè)面開(kāi)始時(shí)機(jī)進(jìn)行預(yù)埋。
          public void watchActivity(Activity activity) {    watchWithMonitorView(activity.getClass().getName(), activity.getWindow().getDecorView());     ... ...    if (activity instanceof android.support.v4.app.FragmentActivity) {            ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(new FragmentLifecycleCallbacks() {                    public void onFragmentViewCreated(android.support.v4.app.FragmentManager fm, final android.support.v4.app.Fragment f, View v,                                                      Bundle savedInstanceState) {                        watchWithMonitorView(f.getClass().getName(), v);                    }
          }), true); } ... ...}
          頁(yè)面監(jiān)控結(jié)束時(shí)機(jī)
          監(jiān)控頁(yè)面根布局 onDraw() 第一次回調(diào),定為頁(yè)面繪制結(jié)束時(shí)機(jī)。
          public void watchWithMonitorView(final String className, final View view) {        final long startTime = System.currentTimeMillis();        final WeakReference viewWeakReference = new WeakReference<>(view);        final ViewTreeObserver.OnDrawListener onDrawListener = new ViewTreeObserver.OnDrawListener() {            Boolean first = true;            @Override            public void onDraw() {                if (startTime != 0 && first && viewWeakReference.get() != null) {                ... ...            }        };        view.getViewTreeObserver().addOnDrawListener(onDrawListener);    }

          2.3.2 分析詳情

          在設(shè)備自動(dòng)化回歸過(guò)程中一個(gè)頁(yè)面會(huì)被多次調(diào)用,在線下監(jiān)控環(huán)境中,只有一個(gè)頁(yè)面3次超過(guò)耗時(shí)閾值( 200ms )才會(huì)算成有效的頁(yè)面卡頓問(wèn)題,防止硬件不穩(wěn)定造成問(wèn)題誤報(bào)。

          三、后臺(tái)問(wèn)題分析

          設(shè)備自動(dòng)化回歸過(guò)程中產(chǎn)生的性能數(shù)據(jù)存在一定的波動(dòng)性,后臺(tái)需要對(duì)批量性能數(shù)據(jù)進(jìn)行算法校驗(yàn),評(píng)估出合理的有效問(wèn)題,減少問(wèn)題誤報(bào)。

          分析工作流程(階段數(shù)據(jù)分析舉例):

          設(shè)備自動(dòng)化回歸過(guò)程采集到階段數(shù)據(jù)后,上傳到移動(dòng)網(wǎng)關(guān),晚上7點(diǎn)啟動(dòng)定時(shí)任務(wù),在后臺(tái)拉取當(dāng)前應(yīng)用版本各個(gè)階段最近n條數(shù)據(jù),進(jìn)行數(shù)據(jù)聚合分析,計(jì)算出合理的階段耗時(shí)平均值,再同樣拉取當(dāng)前應(yīng)用上個(gè)版本各個(gè)階段的最近n條數(shù)據(jù),同樣算出階段耗時(shí)平均值,與當(dāng)前版本階段耗時(shí)平均值進(jìn)行對(duì)比,算出漲跌幅度,如果超出閾值就會(huì)當(dāng)成有效問(wèn)題,進(jìn)行分配與告警。

          四、線下AWACS工具

          在 QA 與開(kāi)發(fā)過(guò)程中, App 上會(huì)懸浮告警 ICON ,開(kāi)發(fā)者可以點(diǎn)擊告警 ICON 打開(kāi)性能監(jiān)控中心進(jìn)行數(shù)據(jù)查看。性能監(jiān)控中心會(huì)展示階段、 ANR 、慢方法、流量、 FPS 等性能數(shù)據(jù),便于開(kāi)發(fā)對(duì)問(wèn)題進(jìn)行排查。

          五、問(wèn)題管理與分配平臺(tái)

          后臺(tái)對(duì)問(wèn)題進(jìn)行分析后,如果是有效問(wèn)題會(huì)落到后臺(tái) db 中,前臺(tái)在 mPaaS 搭建一套問(wèn)題查看與分配 UI 看板,方便業(yè)務(wù)方對(duì)問(wèn)題進(jìn)行處理與狀態(tài)跟進(jìn)。

          5.1 問(wèn)題列表

          APM 監(jiān)控的所有性能指標(biāo)都可以在性能面板中進(jìn)行切換篩選, tab 選中后再結(jié)合應(yīng)用、狀態(tài)、環(huán)境篩選器列出問(wèn)題列表。

          5.2 問(wèn)題詳情

          點(diǎn)擊問(wèn)題列表后跳轉(zhuǎn)到問(wèn)題詳情,問(wèn)題詳情中包含問(wèn)題發(fā)生次數(shù)、進(jìn)度、詳細(xì)信息、設(shè)備基本信息等,協(xié)助開(kāi)發(fā)定位問(wèn)題。
          點(diǎn)擊問(wèn)題詳情右上角“變更狀態(tài)”按鈕,可以變更問(wèn)題狀態(tài),并可選擇負(fù)責(zé)人對(duì)問(wèn)題進(jìn)行分配與跟進(jìn)。

          六、未來(lái)規(guī)劃

          1:監(jiān)控更多維度的數(shù)據(jù),包括 cpu 、線程、子線程更新 UI 等。
          2:增加更多的自動(dòng)化測(cè)試用例,針對(duì)特定的性能場(chǎng)景進(jìn)行獨(dú)立測(cè)試(現(xiàn)在測(cè)試用例基本上都是主流程,覆蓋度還不太夠)。
          3:補(bǔ)齊自動(dòng)化設(shè)備的數(shù)量與型號(hào),通過(guò)多機(jī)型綜合分析性能問(wèn)題。
          4:推廣到公司內(nèi)部使用,協(xié)助解決有贊其他應(yīng)用端性能問(wèn)題。

          end



          ?

          ??
          ?
          瀏覽 62
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美精品久久久 | 人人在日批 | 豆花视频一区二区三区在线观看 | 欧美蜜桃亚洲 | 操b视频免费 |