在移動互聯網時代,由於設備資源受限、網絡不穩定等因素,Web 端和移動端的性能優化顯得尤爲重要,如果性能不好,用戶就容易流失,ToC 的產品尤爲明顯,體驗差的產品必然會被市場淘汰。如何做好性能優化是每個企業都會關注的。

在將於 11 月 24-25 日舉辦的 GMTC 全球大前端技術大會 上,快手性能優化負責人楊凱將會分享 《快手 APM 平臺建設與性能優化》 。他表示,“隨着快手 App 功能越來越多,App 的性能也面臨着嚴峻的挑戰,諸如 App 越來越卡、內存佔用越來越大、包大小不斷增加等各類問題都嚴重影響着用戶體驗”。InfoQ 在會前採訪了楊老師,我們一起來看看快手是如何應對性能挑戰的。

InfoQ:快手 APM 指標監控平臺的建設背景是什麼?目前發展現狀如何?

楊凱:APM 是我們針對快手的性能檢測做的一個監控平臺,其建立背景主要有兩方面 , 一方面有很多用戶反饋在使用我們的 App 時,遇到過卡、閃退和發熱等問題;另一方面,我們從現有數據分析得出結論:性能對於用戶活躍度有着重要影響。

目前,我們已經基本完成了崩潰、內存溢出(OOM)、應用無響應(ANR)、卡頓、啓動、幀率(FPS)、包大小的線上、線下監控,電量、流量等監控正在開發中。線上的話,我們有天級、小時級的監控,並且重點指標有完善的報警機制。對於包大小、啓動等,我們建立了一套實驗室環境,可以監控到每個 mr(Merge request ) 導致的變化,以及日常迭代劣化。

APM 主要解決我們面臨的各種穩定性和性能問題。效果非常明顯:

  • 優化了 40% 的啓動速度,提升了我們的 0 播、留存等關鍵產品數據。
  • 優化了 23M 包大小,大大降低了我們新用戶獲取成本。
  • 兩個優化,都獲得了快手技術線的績效提升獎。

InfoQ:你們在搭建指標監控過程中遇到哪些難點?是怎麼解決的呢?

楊凱:APM 可以做的事情很多,容易鋪得很廣,但每一點都做不透。另一方面,雖然大家都覺得性能重要,但如果沒有數據的支撐,也容易陷入到處救火而看不到成績得窘境。所以我們一方面參考業內經驗、根據數據分析得出重要程度,評估每個方向的優先級,各個擊破,抓住重點,力求每一點都做到極致,並且能從用戶數據上得到充分的體現。

我們是一個音視頻軟件,所以對內存的使用,尤其是 C++ 申請的內存會比較多。內存泄露,OOM、地址空間不足等問題非常突出。業內現有方案對我們來說並不完全適用,需要我們根據自己的實際情況,開發監控、解決問題。業內有比較成熟的 malloc hook 方案監控 C++ 內存的申請、釋放,但我們還需要知道哪些內存不可達,哪些大塊內存被長時間持有,才能更好地解決我們的問題。

另外,我們在線上發現的性能問題,通常不是我們性能組能獨立解決的,需要推動各業務方配合解決。這些工作會給大家日常的開發工作帶來額外的負擔,但它又對我們產品體驗有很重要的影響。所以我們一方面儘量完善工具,上報更多更全的數據,另一方面我們要將大家作爲一個整體團隊,享受項目的成果。

InfoQ:內存優化過程中遇到的問題是如何解決的?

楊凱:我們有一套自己的方法論,即定義問題、分析問題、解決問題、驗收以及防劣化。

定義問題:在最開始階段,先將問題量化,例如用戶卡,就需要定義什麼叫卡,怎麼監控用戶卡?

  • 分析問題: 我們會在收集到足夠的用戶數據後,分析用戶實際的問題場景、原因。
  • 解決問題: 很多問題,並不是性能組可以解決的,但是我們可以提供工具定位、發現問題,推動相關開發人員解決。
  • 驗收: 對於一些重要的優化,我們會通過 AB 上線驗收效果,回收技術數據和產品數據(例如優化 FPS,我們會看相關頁面 CTR 的變化)。
  • 防劣化: 我們會制定一些機制、方案,防止已經優化的數據在日常的迭代中劣化,包括每個版本灰度期間的監控、線下實驗室環境測試、開發階段提醒等。

InfoQ:怎麼進行內存優化?

楊凱:內存主要是 Java 和 C 兩部分,對於 Java,我們研發了一套線上裁剪、分析、上傳用戶本地鏡像的方案,可以做到用戶內存不足時,快速而準確地上報當時的 Java 內存狀態,初步可以判斷出來泄露和內存大戶是誰。上報後我們會對所有用戶的信息做彙總、展示。 Java 部分的內存監控主要做了以下幾點:

  • 內存鏡像轉儲,我們研發了一種高效 dump 方案,解決了傳統方法虛擬機內存轉儲需要暫停虛擬機的問題。
  • 內存鏡像分析,研發了基於 shark 的低內存開銷、低 CPU 開銷的獨立進程解析方案,採用了更爲節省內存的高性能數據結構以及更爲高效的內存索引,增加了同類型對象閾值用於 GC Root 最短路徑搜索剪枝,可以在手機側 10 分鐘內完成 400M 鏡像、200 萬 對象的極端 case 解析。
  • 內存鏡像裁剪,我們研發了一種 hook 虛擬機內存鏡像轉儲時 IO 的高效裁剪方案,解決了傳統裁剪效率低、成功率低的問題,輔以 zstd 壓縮,90% 內存鏡像可以壓縮至 80M 內。

C 的內存我們主要利用編譯器插樁及 malloc hook 記錄所有活着的內存塊,利用 mark-and-sweep 算法在單獨的進程中分析測試應用進程 Native Heap 中不可達的內存塊。將發現的不可達內存上報後臺。具體操作如下:

  • 利用編譯器插樁及 malloc hook 記錄所有活着的內存塊(包含內存塊地址、backtrace 信息),對性能影響較小。
  • 利用 mark-and-sweep 算法在單獨的進程中分析測試應用進程 Native Heap 中不可達的內存塊(包含內存塊地址)。
  • 對於步驟 2 中收集到的不可達內存塊,從 1 中獲取其對應的 backtrace 信息,將泄漏信息上報至 APM 監控平臺。
  • APM 監控平臺解析泄漏信息(backtrace 信息符號化等),做友好的展示,業務方根據 APM 展示信息可快速定位泄漏問題。

InfoQ:如何優化卡頓?

楊凱:我們定義的卡頓是:一個消息 / 任務在主線程執行超過 1s。

優化主要看卡頓的堆棧特徵、當前 CPU 佔用、其它線程正在執行的任務。通常有以下幾種情況:CPU 佔用過高(一般是主線程或者子線程任務重),主線程等鎖(需要看其它線程當時的任務),系統服務忙(binder 調用耗時長)。解決方案一般需要結合場景、頁面,增加 log 等,豐富更多上報信息,定位主要問題,或者緩解 CPU 佔用。

InfoQ:在啓動優化這部分做了哪些動作,優化前後對比效果如何?

楊凱:啓動優化我們主要是建立啓動框架,將啓動所有的任務,全部收斂到框架內,統計每個任務的耗時、相互依賴關係。

啓動優化定位問題:

  • 將啓動時運行的代碼,按照功能,做成 task;
  • 線上收集每個 task 的耗時;
  • 在線下,在 Android 端利用 systrace、在 iOS 端利用自研的火焰圖工具,來分析耗時。

優化手段:

  • 優化整體流程;
  • 分場景、分用戶特性,推遲甚至取消一些 task (根據用戶登錄狀態,用戶使用習慣,後面我們會用機器學習預測 task 是否需要初始化);
  • 特別關注一些鎖的等待、主線程 CPU 分配不足等問題;
  • 一些系統 API,背後會引發一系列的初始化(setcookie,會引起 WebView 內核初始化);
  • 主動 dex2oat;
  • 二進制重排、dex 重排。

另外, 針對線上收集到的信息,重點優化耗時較多的任務。 線下通過 systrace 等工具,定位、驗證修復。然後依據用戶的不同特徵,初始化不同任務。例如,未登錄用戶不需要初始化拍攝相關任務。 我們一期優化效果達到了 40% ,後續幾期優化,也收到了不錯的效果。用戶側收益明顯,用戶(尤其是新用戶)0 展示 、0 滑、 0 播放,以及留存等數據都有非常大的提升。

嘉賓介紹

楊凱,快手技術專家,客戶端性能穩定性負責人。2017 年加入快手,先後負責快手海外版、性能穩定性。現在主要負責快手雙端穩定性、性能優化,專注於提升快手可用性、易用性,提升用戶使用的滿意度,爲公司高速發展保駕護航。團隊成員均來自於一線互聯網公司、主流手機廠商,對 Android 核心技術有着深入的理解和豐富的經驗。

關注 GMTC 全球大前端技術大會 ,迅速 get百度、快手、高德的最新性能優化的技術實踐。

相關文章