得物App白屏優(yōu)化系列|圖片庫(kù)篇
一、背景
圖片加載作為重中之重的App體驗(yàn)指標(biāo),端側(cè)的白屏問題則是其中最為嚴(yán)重的問題之一。想象一下如果你在瀏覽交易商品、社區(qū)帖子等核心場(chǎng)景下,圖片無法完成加載是多么糟糕的體驗(yàn),線上過往也陸續(xù)有一些白屏的用戶反饋。
客戶端架構(gòu)側(cè)從用戶白屏問題反饋出發(fā),深入分析每一個(gè)用戶的實(shí)際情況,從0到1完成了白屏體系監(jiān)控建設(shè),借助獨(dú)立搭建的白屏分析平臺(tái)能力,從圖片庫(kù)、網(wǎng)絡(luò)庫(kù)、CDN質(zhì)量等3個(gè)維度進(jìn)行了專項(xiàng)治理優(yōu)化。本文重點(diǎn)帶你了解得物圖片庫(kù)是如何完成白屏精細(xì)化監(jiān)控的基礎(chǔ)能力、問題定位、治理優(yōu)化,實(shí)現(xiàn)線上用戶白屏問圖片庫(kù)相關(guān)Issue反饋基本清零。
二、白屏監(jiān)控體系
眾所周知,圖片加載全鏈路是橫跨圖片庫(kù)、網(wǎng)絡(luò)庫(kù)、多云CDN質(zhì)量等核心基建的長(zhǎng)鏈路過程。故白屏監(jiān)控體系建設(shè)也是基于以上3個(gè)維度進(jìn)行同步展開,實(shí)現(xiàn)白屏各類歸因問題的點(diǎn)對(duì)點(diǎn)跟進(jìn),以下為當(dāng)前得物側(cè)在平臺(tái)歸因、端側(cè)監(jiān)控能力建設(shè)、端側(cè)問題治理上的一些實(shí)踐匯總。
平臺(tái)歸因問題
全局監(jiān)控能力建設(shè)
端側(cè)優(yōu)化手段
三、圖片庫(kù)監(jiān)控能力
圖片庫(kù)作為圖片請(qǐng)求的起始發(fā)起者 & 圖片加載的最終使用者,是唯一一個(gè)可以監(jiān)控、匯總完整鏈路數(shù)據(jù)的承載者。而得物當(dāng)前的白屏監(jiān)控也是基于圖片加載流程深度剖析,形成了多圖、單圖的加載白屏監(jiān)控能力,將白屏問題拆解到多個(gè)細(xì)分子階段,輸出結(jié)構(gòu)化的分析日志,最終打通到平臺(tái)側(cè)進(jìn)行問題聚合分析。
圖片
多圖監(jiān)控
定義為屏幕上10秒內(nèi)有7張圖未走完圖片庫(kù)的完整流程,則觸發(fā)多圖監(jiān)控上報(bào)。
基于Fresco的producer(階段信息)、reqeust(請(qǐng)求信息)、submit(加載信息)回調(diào)能力封裝,我們記錄了每一張圖片階段開始、結(jié)束、失敗、取消等詳細(xì)時(shí)間信息、額外圖片參數(shù)信息等到內(nèi)存Map中備用。
通過Handler消息循環(huán)模型,每秒發(fā)送1個(gè)探測(cè)消息,對(duì)加載成功、離開屏幕、內(nèi)存緩存復(fù)用等無關(guān)場(chǎng)景進(jìn)行剔除過濾,達(dá)到監(jiān)控手機(jī)屏幕上失敗請(qǐng)求、加載中請(qǐng)求的目的,觸發(fā)到我們10s 7圖的閾值后則進(jìn)行所有圖片信息的聚合上報(bào),可以清晰直觀的知道圖片加載阻塞的卡點(diǎn)、失敗的原因。
圖片
圖片核心信息記錄:
圖片
- Producer信息中記錄圖片經(jīng)歷所有任務(wù)處理階段: 線程切換、內(nèi)存緩存、磁盤緩存、網(wǎng)絡(luò)請(qǐng)求、編解碼等。
- Request信息中記錄了圖片開始請(qǐng)求、取消、失敗的核心時(shí)間節(jié)點(diǎn)。
- Submit信息中記錄了圖片上屏、完成加載、離開屏幕等核心時(shí)間節(jié)點(diǎn)。
- PixelCopy信息記錄了最近一次屏幕的截屏信息,可以較為真實(shí)反應(yīng)當(dāng)前屏上圖片的時(shí)機(jī)情況,同時(shí)平臺(tái)對(duì)此進(jìn)行了像素點(diǎn)的分析,本篇重點(diǎn)介紹圖片庫(kù)相關(guān)的監(jiān)控能力,在此不做過多的闡述。
以下為聚合格式化后圖片加載的本地日志與平臺(tái)實(shí)例參考,可以直接了當(dāng)?shù)闹缊D片是由于網(wǎng)絡(luò)階段導(dǎo)致的白屏。
pixelCopy像素圖
圖片
producer時(shí)序信息
單圖慢加載監(jiān)控
定義為單張圖3s內(nèi)未走完除網(wǎng)絡(luò)外的子階段、10s未完成完整階段,則觸發(fā)單圖慢加載上報(bào)。
單圖監(jiān)控的邏輯相對(duì)簡(jiǎn)單,當(dāng)圖片加載狀態(tài)變化時(shí),基于圖片庫(kù)ImagePerfData的信息回調(diào)進(jìn)行數(shù)據(jù)整合。
- 記錄當(dāng)前圖片加載階段、狀態(tài)、線程、耗時(shí)、單圖信息、配置信息等,仍舊通過handler消息循環(huán)每1s發(fā)送一個(gè)探測(cè)消息,確認(rèn)屏上圖片是否觸發(fā)慢加載。
圖片
大盤采樣監(jiān)控
等待圖片完整加載階段(成功、失?。┖蠡谟脩舨蓸用?,將圖片加載信息記錄上報(bào),以衡量圖片全局加載質(zhì)量。
圖片大盤采樣監(jiān)控實(shí)現(xiàn)邏輯與多單圖原理類似,此處主要介紹一些大盤核心元信息。
圖片
四、圖片庫(kù)優(yōu)化治理
基于圖片庫(kù)基礎(chǔ)監(jiān)控、白屏監(jiān)控平臺(tái)的建設(shè)以及線上用戶的反饋,我們發(fā)現(xiàn)了各種bad case導(dǎo)致端側(cè)白屏現(xiàn)象,并對(duì)其進(jìn)行了精細(xì)化的點(diǎn)對(duì)點(diǎn)分析,包括圖片、網(wǎng)絡(luò)、CDN質(zhì)量三大環(huán)節(jié),其中66%為網(wǎng)絡(luò)問題,4.5%為圖片問題,1.3%為CDN問題。
本篇重點(diǎn)介紹圖片庫(kù)問題相關(guān)的治理優(yōu)化。
圖片
系統(tǒng)解碼優(yōu)化
來看一個(gè)有意思的bad case,在線下bvt體驗(yàn)過程中,我們發(fā)現(xiàn)在頻繁刷新得物Tab的情況下,會(huì)出現(xiàn)端上圖片均無法加載的極端情況。查看本地日志發(fā)現(xiàn),圖片庫(kù)的階段日志均停留在DecodeProducer解碼階段。
圖片
通過本地多圖監(jiān)控日志可以看到,解碼線程池任務(wù)已經(jīng)提交,但實(shí)際解碼處理并沒有執(zhí)行,說明解碼線程池的當(dāng)前執(zhí)行任務(wù)出了問題。
由于是線下問題,debug發(fā)現(xiàn)極個(gè)別圖片由于包含iccData數(shù)據(jù),按現(xiàn)有邏輯會(huì)執(zhí)行到系統(tǒng)解碼流程中。而在對(duì)應(yīng)設(shè)備上(尤其是android 8.1.0)系統(tǒng)頻繁進(jìn)行Heif解碼,整個(gè)解碼流程可能會(huì)變得極其緩慢。我們查看線程堆棧發(fā)現(xiàn)執(zhí)行任務(wù)會(huì)直接Block在BitmapFactory.nativeDecodeStream方法中,導(dǎo)致解碼線程池長(zhǎng)時(shí)間阻塞,最終引起頁(yè)面白屏。
圖片
- iccData數(shù)據(jù): 圖片的顏色配置信息,告知端上渲染時(shí)的色彩特性。
現(xiàn)有LibHeif & 三方Heif解碼庫(kù) 均無法有效處理對(duì)應(yīng)icc數(shù)據(jù)段,會(huì)導(dǎo)致個(gè)別圖片存在一定程度的色差問題。
優(yōu)化方案:
調(diào)整解碼流程,忽略iccData數(shù)據(jù)可能會(huì)導(dǎo)致的色差問題,將所有的解碼任務(wù)均托管到解碼庫(kù)執(zhí)行。
圖片
收益:
新版本系統(tǒng)慢解碼(尤其android 8.1.0)導(dǎo)致的白屏未再出現(xiàn)。
圖片請(qǐng)求優(yōu)先級(jí)改造
為了提高屏上圖片加載速度,得物側(cè)使用了圖片預(yù)加載能力。在過往的預(yù)加載、上屏請(qǐng)求管理中,使用的是Fresco PriorityNetworkFetcher來處理預(yù)加載與上屏請(qǐng)求的優(yōu)先級(jí),所有的圖片請(qǐng)求共享一個(gè)最大并發(fā)數(shù)為12的網(wǎng)絡(luò)請(qǐng)求隊(duì)列,這在實(shí)踐中我們發(fā)現(xiàn)了大量由于A域名不同,導(dǎo)致B域名請(qǐng)求無法成功導(dǎo)致的白屏。
圖片
基于得物當(dāng)前是多CDN、預(yù)加載&上屏請(qǐng)求互相轉(zhuǎn)換 的請(qǐng)求現(xiàn)狀,存在以下問題:
- 多域名請(qǐng)求間的競(jìng)爭(zhēng)問題,A域名不通會(huì)導(dǎo)致并發(fā)隊(duì)列被打滿,B域名網(wǎng)絡(luò)正常但請(qǐng)求始終處在等待入隊(duì)狀態(tài)。
- 預(yù)加載進(jìn)入請(qǐng)求隊(duì)列后,在弱網(wǎng)等狀態(tài)下并不能為上屏請(qǐng)求讓步,擠占了一部分的運(yùn)行時(shí)請(qǐng)求隊(duì)列空間。
- 預(yù)加載的請(qǐng)求會(huì)無上限堆積,快速滑動(dòng)場(chǎng)景可能出現(xiàn)由于持續(xù)存在屏上圖片加載,預(yù)加載請(qǐng)求會(huì)堆積到200-300+,但實(shí)際并沒有有效利用到預(yù)加載轉(zhuǎn)化后的Bitmap,浪費(fèi)了帶寬 & 流量。
優(yōu)化方案:
去除圖片庫(kù)的優(yōu)先級(jí)隊(duì)列限制,統(tǒng)一交由網(wǎng)絡(luò)庫(kù)管理收口。
- 實(shí)現(xiàn)按域名拆解host請(qǐng)求,充分利用網(wǎng)絡(luò)庫(kù)的現(xiàn)有能力,打破域名間競(jìng)爭(zhēng)。
- 支持預(yù)加載、離屏的"請(qǐng)求取消"能力 & 圖片庫(kù)上離屏標(biāo)記、請(qǐng)求狀態(tài)轉(zhuǎn)換。
圖片
收益:
- 端側(cè)圖片庫(kù)的請(qǐng)求平均排隊(duì)耗時(shí)降 88%,圖片請(qǐng)求全鏈路降低 50%。
- 解決CDN單通導(dǎo)致的白屏問題,線上CDN單通異常數(shù)量呈下降趨勢(shì)。
動(dòng)圖渲染幀處理重構(gòu)
得物歷史對(duì)動(dòng)圖渲染幀的準(zhǔn)備、加載流程,不同于Fresco原生For循環(huán)實(shí)現(xiàn),自定義實(shí)現(xiàn)了利用Handler消息調(diào)度來分發(fā)、準(zhǔn)備渲染幀。
問題發(fā)現(xiàn)
利用自研的白屏平臺(tái)監(jiān)控能力,聚合分析了圖片慢解碼導(dǎo)致白屏的Issue,發(fā)現(xiàn)有一類case用戶會(huì)出現(xiàn)解碼任務(wù)始終不完成的情況,出現(xiàn)概率大概在萬分之二。我們對(duì)解碼流程監(jiān)控進(jìn)行了增強(qiáng)處理,進(jìn)行線程池監(jiān)控,記錄解碼線程的運(yùn)行數(shù)量、id、等待隊(duì)列數(shù)量等信息附帶在多圖監(jiān)控的白屏上報(bào)中。
圖片
圖片
可以看到,解碼線程池并發(fā)數(shù)8已經(jīng)被打滿,但等待隊(duì)列中囤積的解碼圖片數(shù)量有1200+。
白屏問題轉(zhuǎn)化為了監(jiān)控解碼線程池運(yùn)行中的任務(wù)究竟在干什么,有了之前系統(tǒng)解碼的分析經(jīng)驗(yàn),我們?nèi)绻苯訉灼羻栴}當(dāng)做一個(gè)Crash問題來分析呢?那么很自然地會(huì)想到去查看堆棧,只要dump運(yùn)行時(shí)中的線程池id所對(duì)應(yīng)的堆棧即可。
圖片
最終通過堆棧結(jié)合代碼分析確認(rèn)是由于動(dòng)圖幀渲染的countDownLatch鎖在極端case下無法釋放,線程池逐步被打滿導(dǎo)致的等待隊(duì)列解碼任務(wù)無法得到執(zhí)行造成的白屏,而背景恰好是對(duì)應(yīng)版本的動(dòng)圖下發(fā)數(shù)量明顯上漲導(dǎo)致此類case逐漸暴露,與我們的結(jié)論能夠吻合。
圖片
優(yōu)化方案
歷史代碼存在以下幾個(gè)問題:
- 單幀Bitmap毫秒級(jí)的準(zhǔn)備處理周期內(nèi),在View OnPause情況下未完成便退出,會(huì)導(dǎo)致當(dāng)前線程鎖無法釋放。
- countDownLatch的鎖邏輯可通過回調(diào)的方式代替。
- 線程池復(fù)用解碼線程池,導(dǎo)致動(dòng)圖加載邏輯異常會(huì)影響到所有圖片。
圖片
圖片
優(yōu)化后:對(duì)動(dòng)圖幀渲染邏輯進(jìn)行去鎖改造,采用callBack回調(diào)方式進(jìn)行動(dòng)圖幀分發(fā)處理,同時(shí)對(duì)解碼線程池進(jìn)行隔離處理。
圖片
收益:
App新版本動(dòng)圖閉鎖邏輯導(dǎo)致的白屏歸因數(shù)量從原有1000+實(shí)現(xiàn)清零。
磁盤全局鎖優(yōu)化
圖片庫(kù)的磁盤設(shè)計(jì)基于Fresco原生實(shí)現(xiàn),支持大小緩存,但讀、寫、刪、遍歷操作同時(shí)共用Object Lock對(duì)象鎖,且過往由于業(yè)務(wù)需要獲取緩存文件的能力,圖片庫(kù)暴露了getCacheFile的API給到上層使用。
圖片
白屏平臺(tái)發(fā)現(xiàn)存在磁盤讀寫超時(shí)導(dǎo)致的圖片白屏。通過對(duì)DiskProducer的深入代碼分析,我們將問題鎖定在了圖片庫(kù)存在大量本地磁盤文件的情況下,由于Fresco原生邏輯每隔30min要進(jìn)行磁盤IO遍歷更新圖片庫(kù)當(dāng)前磁盤緩存大小,可能會(huì)導(dǎo)致長(zhǎng)時(shí)間持有對(duì)象鎖,最終引起圖片加載流程持續(xù)等待遍歷完成的白屏。
圖片
優(yōu)化方案
磁盤遍歷是Fresco的磁盤緩存模型中唯一潛在的長(zhǎng)耗時(shí)點(diǎn)。
由于此操作的調(diào)用頻率極低(30min一次),我們嘗試針對(duì)IO遍歷進(jìn)行標(biāo)記,并調(diào)整了原有主線程獲取磁盤緩存文件 & Fresco原生磁盤緩存查找的邏輯,對(duì)于在緩存遍歷期間磁盤數(shù)量超過指定閾值的緩存讀取操作進(jìn)行適當(dāng)忽略。
當(dāng)然終極優(yōu)化方案是降低磁盤緩存模型的鎖粒度,將全局的對(duì)象鎖降至單文件級(jí)別,但對(duì)現(xiàn)有的磁盤緩存設(shè)計(jì)改動(dòng)過大暫時(shí)未上線。
圖片
收益:
新版本磁盤鎖導(dǎo)致的主線程卡頓清零 & 磁盤鎖導(dǎo)致的圖片加載長(zhǎng)耗時(shí)降低50% 。
元信息讀取適配
部分設(shè)備上Heif圖編碼時(shí)獲取圖片metadata寬高元信息失敗,導(dǎo)致無法完成正常解碼、resize裁剪等操作,最終形成圖片加載白屏。
我們先來看下圖片庫(kù)歷史編碼流程環(huán)節(jié),在網(wǎng)絡(luò)請(qǐng)求完成后,會(huì)通過BitmapFactory進(jìn)行圖片metadata信息,獲取期望的寬高數(shù)據(jù)。在歷史邏輯中,我們只單獨(dú)處理了webp圖片寬高讀取,Heif圖等其他格式仍舊采用系統(tǒng)兜底實(shí)現(xiàn),但實(shí)際針對(duì)加載失敗的原圖分析后,我們發(fā)現(xiàn)andorid系統(tǒng)BitmapFactory的解析邏輯對(duì)Heif圖片的支持并不友好,會(huì)存在獲取失敗的bad case。
final Pair<Integer, Integer> dimensions;
if (DefaultImageFormats.isWebpFormat(imageFormat)) {
//webp圖片單獨(dú)處理
dimensions = readWebPImageSize();
} else {
//系統(tǒng)兜底實(shí)現(xiàn)
dimensions = readImageMetaData().getDimensions();
}
故我們需要重Heif圖的寬高元信息獲取邏輯,實(shí)際獲取邏輯在三方SDK或者libHeif開源庫(kù)在native層完成了封裝,F(xiàn)resco上層走調(diào)用結(jié)構(gòu)解析,分別對(duì)應(yīng)寬度、高度、旋轉(zhuǎn)角度、旋轉(zhuǎn)方向、是否動(dòng)圖等,同時(shí)在獲取解析結(jié)果異常的情況下,我們?nèi)耘f以系統(tǒng)BitmapFactory進(jìn)行流解析兜底。
final Pair<Integer, Integer> dimensions;
if (imageFormat.getName().equals(DefaultImageFormats.HEIFC.getName())) {
//部分設(shè)備的 系統(tǒng)實(shí)現(xiàn)讀取很慢且無法解析
dimensions = readHeifFormatImageSizeForSimple(imageFormat);
} else if (DefaultImageFormats.isWebpFormat(imageFormat)) {
dimensions = readWebPImageSize();
} else {
dimensions = readImageMetaData().getDimensions();
}
//寬高、旋轉(zhuǎn)方向、是否為多幀hefi動(dòng)圖等信息
try {
int[] parseResult = imageFormat.readHeifFormatImageSizeForSimple(inputStream);
if (parseResult != null) {
this.mWidth = parseResult[0];
this.mHeight = parseResult[1];
this.mRotationAngle = JfifUtil.transformFromClockWiseToAntiClockWise(parseResult[2]);
this.mExifOrientation = JfifUtil.getExifOrientationFromAutoRotateAngle(this.mRotationAngle);
int isSequence = parseResult[3];
if (isSequence == 0) {
this.mImageFormat = imageFormat.getHeifFormatAnimated();
}
} else {
//系統(tǒng)實(shí)現(xiàn)異常兜底
return readImageMetaData().getDimensions();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException ignored) {
}
}
異常加載圖截屏
開源libHeif的內(nèi)部實(shí)現(xiàn)
三方Heif的jni實(shí)現(xiàn)
至此,個(gè)別問題設(shè)備的Heif慢加載、無法加載問題得到了有效解決。
收益:
個(gè)別Rom設(shè)備dimension(圖片寬高)無法解析的異常上報(bào)基本清零,新版本該類型的白屏、慢加載從800+降至0。
內(nèi)存觸頂降級(jí)優(yōu)化
除了大面積白屏外,內(nèi)存不足導(dǎo)致的圖片加載失敗也是一個(gè)常見問題。
動(dòng)圖降級(jí)
Fresco原生提供了PoolStatsTracker類來監(jiān)控在分配內(nèi)存過程中是否觸發(fā)到緩存池定義的內(nèi)存上限,定義了當(dāng)前緩存池的使用量,以及onHardCapReached的觸頂回調(diào)。而我們當(dāng)前則是在回調(diào)中,進(jìn)行一次主動(dòng)GC來保證系統(tǒng)回收未持有引用的bitmap & 其他內(nèi)存,同時(shí)標(biāo)記規(guī)定間隔內(nèi)(如1min內(nèi))限制大動(dòng)圖的內(nèi)存分配,將其強(qiáng)制轉(zhuǎn)為靜圖。
圖片
圖片
低內(nèi)存 & 低磁盤緩存清理
基于application ComponentCallbacks2的低內(nèi)存回調(diào)進(jìn)行磁盤&內(nèi)存緩存清理。
override fun onLowMemory() {
val imagePipeline = Fresco.getImagePipelineFactory().imagePipeline
imagePipeline.config.executorSupplier.forBackgroundTasks().execute {
if (DuImageGlobalConfig.isDiskNervous) {
imagePipeline.clearDiskCaches()
}
imagePipeline.clearMemoryCaches()
}
}
override fun onTrimMemory(level: Int) {
val imagePipeline = Fresco.getImagePipelineFactory().imagePipeline
imagePipeline.config.executorSupplier.forBackgroundTasks().execute {
if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
if (DuImageGlobalConfig.isDiskNervous) {
imagePipeline.clearDiskCaches()
}
}
if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
imagePipeline.clearMemoryCaches()
}
}
}
其他內(nèi)存優(yōu)化手段
關(guān)于圖片內(nèi)存得物還做了很多優(yōu)化,但非觸頂場(chǎng)景下往往不會(huì)直接導(dǎo)致白屏,在此可以關(guān)注后續(xù)技術(shù)博客,如:
- 三級(jí)緩存閾值配置分檔
- Android8以下bitmap內(nèi)存轉(zhuǎn)移到Native層
- 大動(dòng)圖、大靜圖治理
- 圖片Resize兜底裁剪、云端分級(jí)裁剪
- BitmapConfig低端機(jī)降級(jí)
- ....
主線程慢消息治理
在白屏平臺(tái)監(jiān)控中,還發(fā)現(xiàn)一類圖片庫(kù)已經(jīng)完成onFinalImageSet回調(diào),但最終pixelCopy的像素圖展示為白屏的情況。我們先來了解一下原有的圖片加載流程,根據(jù)流程可知我們已經(jīng)調(diào)用了圖片setImage設(shè)置,懷疑是頁(yè)面慢渲染導(dǎo)致的白屏。
圖片
//圖片庫(kù)完成所有producer處理流程后的回調(diào)
private void onNewResultInternal(
String id,
DataSource<T> dataSource,
@Nullable T image,
float progress,
boolean isFinished,
boolean wasImmediate,
boolean deliverTempResult) {
//....
if (isFinished) {
logMessageAndImage("set_final_result @ onNewResult", image);
mDataSource = null;
if (mSettableDraweeHierarchy != null){
mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate); //setImage調(diào)用
}
reportSuccess(id, image, dataSource); //上報(bào)圖片完成屏上設(shè)置,即onFinalImageSet完成
}
//....
}
白屏問題隨即轉(zhuǎn)化為卡頓問題,分析卡頓問題的利器則是APM火焰圖能力,故我們對(duì)"圖片加載完成"但仍舊白屏的case進(jìn)行火焰圖的聚合上報(bào)。發(fā)現(xiàn)主線程的確存在長(zhǎng)耗時(shí)消息,問題最終轉(zhuǎn)化為了主線程的慢消息治理,以下列舉一下我們已經(jīng)發(fā)現(xiàn)并實(shí)際解決的問題。
圖片
- 頁(yè)面未接入X2c導(dǎo)致inflate耗時(shí)
- GetCacheFile的主線程調(diào)用耗時(shí)
- Sp的主線程強(qiáng)制寫文件
- LoadSo成功后的字體文件主線程直接加載
- 主線程查詢native視頻緩存
- ....
收益:
主線程慢消息導(dǎo)致圖片View慢渲染白屏下降80%。
五、總結(jié)
白屏問題作為長(zhǎng)鏈路綜合型問題,往往問題都是萬分之幾的出現(xiàn)概率,這意味著線下想要復(fù)現(xiàn)排查問題的難度極大,所以如何有效分析歸因解決白屏問題對(duì)我們來說是不小的挑戰(zhàn)。
在歷史監(jiān)控能力缺失無法有效歸因的背景下,我們通過線上白屏用戶的問題分析,一步步完善端側(cè)白屏全鏈路的日志能力,逐步摸索建立起基于端側(cè)圖片、網(wǎng)絡(luò)、CDN信息的白屏監(jiān)控平臺(tái),實(shí)現(xiàn):
- 白屏問題的線上反饋歸因率達(dá)到100%,無不明確或猜測(cè)的歸因;
- 白屏問題的分析時(shí)效從無法分析到2-3小時(shí)級(jí)別,到現(xiàn)有的5-10min內(nèi);
- 白屏問題線上反饋從歷史單月7~10例反饋,到截止目前2個(gè)月以來線上0反饋。
本文簡(jiǎn)要介紹了在白屏監(jiān)控能力建設(shè)過程中,圖片庫(kù)在編解碼流程、緩存讀取策略、視圖渲染加載等階段所做的一些優(yōu)化。但白屏問題的治理遠(yuǎn)遠(yuǎn)不局限于圖片庫(kù)本身,后續(xù)會(huì)陸續(xù)為大家介紹我們?cè)诰W(wǎng)絡(luò)優(yōu)化、CDN質(zhì)量監(jiān)控、白屏平臺(tái)打磨等環(huán)節(jié)所落地的實(shí)踐。