在這樣一個注重使用者體驗的時代,APM
技術快速發展,國內更是百花齊放,最近對各個公司的 APM
產品有一個調研,並在此基礎上進行了自己的實踐。這裡就從 iOS 的角度出發,談談自己對移動端 APM 的技術上的理解,並提供相對應的例項。
何為 APM
APM
的全稱是Application performance management
,即應用效能管理,通過對應用的可靠性、穩定性等方面的監控,進而達到可以快速修復問題、提高使用者體驗的目的。
國內各大公司都有自己的一套監控體系,這個系統可能是自己研發,也可能是第三方提供,當然對於這個資料為王的時代,很多有實力的公司傾向於自主研發,掌握核心資料。比較有代表性的 APM 產品有:聽雲、阿里百川、騰訊 bugly、NewRelic、OneAPM、網易雲捕等
說到監控,那麼指標是我們所關注的呢?如下所示
- 網路請求:成功率、狀態碼、流量、網路響應時間、HTTP與HTTPS的 DNS 解析、TCP握手、SSL握手(HTTP除外)、首包時間等時間
- 介面卡頓、卡頓堆疊
- 崩潰率、崩潰堆疊
- Abort 率:也就是由於記憶體過高的等原因,被系統殺死的情況
- 互動監控:頁面載入時間、頁面的互動痕跡
- 維度資訊:地域、運營商、網路接入方式、作業系統、應用版本等
- 其他:記憶體、幀率、CPU使用率、啟動時間、電量等
聊聊原理
卡頓檢測
當應用發生卡頓的時候,一般會伴隨著掉幀,所以幀率是最容易想到的指標來判斷卡頓。對於線下的測試環境,我們可以使用幀率來對開發做一些提示,告訴他們可能發生了卡頓。但是幀率不穩定性較高,所以一般會採取另一種方式來做卡頓檢測。那就是Runloop,對於細節可以檢視 Runloop
原始碼,會發現對於事件的處理主要就是在kCFRunLoopBeforeSources
和kCFRunLoopBeforeWaiting
狀態之間,還有kCFRunLoopAfterWaiting
之後。那我們就可以對兩個狀態進行監控,如果消耗時間太久,就代表著卡頓的發生。
上圖摘自阿里百川,如圖所示,我們會對卡頓次數做一個判斷,如果次數為1,但時間超時,則為單次耗時較長的卡頓,如果次數到達閥值,則證明是連續短時間卡頓。
當卡頓發生之後,我們為了定位,會收集當時的一個堆疊情況,在此你可以使用 PLCrashReporter
來做,也可以自己研發一個堆疊收集庫(可參考這裡來做)
對於例項,網上已經有很多開源的專案,你可以參考這個
崩潰檢測
對於崩潰的情況,一般是由 Mach
異常或 Objective-C
異常(NSException)引起的。我們可以針對這兩種情況抓取對應的 Crash
事件。
Mach 異常捕獲
如果想要做mach
異常捕獲,需要註冊一個異常埠,這個異常埠會對當前任務的所有執行緒有效,如果想要針對單個執行緒,可以通過 thread_set_exception_ports
註冊自己的異常埠,發生異常時,首先會將異常拋給執行緒的異常埠,然後嘗試拋給任務的異常埠,當我們捕獲異常時,就可以做一些自己的工作,比如,當前堆疊收集等。
對於如何註冊一個異常埠,這裡有示意圖和 PLCrashReporter 可以參考
Unix 訊號捕獲
對於Mach 異常,作業系統會將其轉換為對應的 Unix訊號,所以如果你對Mach
不熟悉的話,也可以通過註冊signalHandler
的方式來做訊號異常。對於例項,你可以參考這裡
signal(SIGHUP, signalHandler);
signal(SIGINT, signalHandler);
signal(SIGQUIT, signalHandler);
signal(SIGABRT, signalHandler);
signal(SIGILL, signalHandler);
signal(SIGSEGV, signalHandler);
signal(SIGFPE, signalHandler);
signal(SIGBUS, signalHandler);
signal(SIGPIPE, signalHandler);
複製程式碼
NSException 捕獲
對於NSException
異常,也比較容易處理,通過註冊NSUncaughtExceptionHandler
捕獲異常資訊即可,將拿到的NSException
細節寫入Crash
日誌,上傳到後臺做資料分析
// register the uncaught exception handler
NSSetUncaughtExceptionHandler(&handler);
複製程式碼
Abort 率檢測
目前對於記憶體過高被殺死的情況是沒有辦法直接統計的,一般通過排除法來做百分比的統計,原理如下
- 程式啟動,設定標誌位
- 程式正常退出,清楚標誌
- 程式
Crash
,清楚標誌 - 程式電量過低導致關機,這個也沒辦法直接監控,可以加入電量檢測來輔助判斷
- 第二次啟動,標誌位如果存在,則代表
Abort
一次,上傳後臺做統計
互動監控
對於頁面的載入時間,這個比較容易實現,直接通過Runtime hook
對應的生命週期方法即可,比如 viewDidLoad
、viewWillAppear
等
對於使用者的互動痕跡,比如點選了那個按鈕、跳轉到了那個頁面,這些資訊偏於使用者行為的收集,我們也獨立研發了一個無埋點的SDK,專門來做使用者行為資料的收集與分析,核心也是基於 hook AOP
的思想。細節可以參考我同事的作品
網路監控
對於成功率、狀態碼、流量,以及網路的響應時間之類的,我們可以主要可以通過兩種方式來做
- 針對
URLConnection
、CFNetwork
、NSURLSession
三種網路做Hook
,hook
的具體技術可以是method swizzle
也可以是Proxy
、Fishhook
之類的 - 也可以使用
NSURLProtocol
對網路請求的攔截,進而得到流量、響應時間等資訊,但是NSURLProtocol
有自己的侷限,比如NSURLProtocol
只能攔截NSURLSession
,NSURLConnection
以及UIWebView
,但是對於CFNetwork
則無能為力
對於第一種方式可以Hook
哪些方法的,可以參考這個圖
對於 HTTP與HTTPS 的 DNS 解析、TCP握手、SSL握手(HTTP除外)、首包時間等時間的統計,稍有難度
但是,因為我們所使用的URLConnection
、CFNetwork
、NSURLSession
底層都是 BSDSocket
,所以可以嘗試在socket
上動手腳來實現效果,類似於通過ViewController
的生命週期方法來統計頁面載入時間的做法,我們Hook socket
相關的方法來做,比如通過hook
socket
連線時的 connect
方法,拿到tcp
握手的起始時間,通過hook
SSLHandshake
方法,在SSLHandshake
執行的時候拿到 SSL
握手的起始時間等。目前聽雲已經提供了 HTTP
的分段時間查詢功能,大家去體驗下
int connect(int, const struct sockaddr *, socklen_t) __DARWIN_ALIAS_C(connect);
OSStatus SSLHandshake(SSLContextRef ctx)
複製程式碼
但是對於 iOS 9 Apple 加入 ATS 新特性,並要求開發者使用 HTTPS,我在 iOS9、10上對 HTTPS 網路請求Hook socket
方法時候,有一些方法hook
失效,猜想應該是Apple 進行了加固、加密,導致一些系統方法沒辦法hook
,所以在 iOS9、10 上無法通過socket
來取得HTTPS
網路的分段時間(糾正:fishhook 無法 hook socket 的原因:https://github.com/facebook/fishhook/issues/40)
不過apple
在 iOS 10 推出一個API
,可以在 iOS10 版本以上進行網路資訊的收集
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
複製程式碼
列印結果如下
(Fetch Start) 2017-02-24 09:03:06 +0000
(Domain Lookup Start) 2017-02-24 09:03:06 +0000
(Domain Lookup End) 2017-02-24 09:03:06 +0000
(Connect Start) 2017-02-24 09:03:14 +0000
(Secure Connection Start) 2017-02-24 09:03:14 +0000
(Secure Connection End) 2017-02-24 09:03:16 +0000
(Connect End) 2017-02-24 09:03:16 +0000
(Request Start) 2017-02-24 09:03:16 +0000
(Request End) 2017-02-24 09:03:16 +0000
(Response Start) 2017-02-24 09:03:16 +0000
(Response End) 2017-02-24 09:03:16 +0000
複製程式碼
當然,對於網路各層次的時間獲取,如果你有好的方案,希望您可以留言告知。同時對於一些維度資訊和記憶體等基礎指標,很容易獲取,這裡就不細談了
大禮包
在調研和學習APM技術的過程中,發現了很多優秀的部落格,所以在此推薦給大家,有需要的可以自取