在这样一个注重用户体验的时代,APM技术发展迅猛,百花齐放。最近有一个关于各个公司的APM产品的调查,在此基础上,我进行了自己的研究。实践。在这里,我将从iOS的角度,谈谈我对移动端APM的技术理解,并提供相应的例子。APMAPM的全称是Applicationperformancemanagement,即应用性能管理。通过监控应用的可靠性和稳定性,快速修复问题,提升用户体验。国内各大公司都有自己的监控系统,可能是自己开发的,也可能是第三方提供的。当然,在这个数据为王的时代,很多有实力的企业都倾向于自主研发,掌握核心数据。代表性的APM产品有:听云、阿里百川、腾讯bugly、NewRelic、OneAPM、网易Yuncatch等。谈到监控,我们关注哪些指标?网络请求如下:成功率、状态码、流量、网络响应时间、HTTP和HTTPS的DNS解析、TCP握手、SSL握手(HTTP除外)、首包时间等接口冻结、冻结堆栈崩溃率、崩溃stackAbortrate:即内存过大交互监控:页面加载时间,页面交互轨迹维度信息:地区,运营商,网络接入方式,操作系统,应用版本等其他:内存,帧率,CPU占用率,启动时间、电量等说一下卡顿检测的原理应用程序卡顿时,通常会伴随丢帧,所以帧率是最容易判断卡顿的指标。对于离线测试环境,我们可以通过帧率给开发一些提示,告诉他们可能出现了卡顿。但由于帧率不稳定,所以一般采用另一种方法进行卡顿检测。那就是Runloop。具体可以查看Runloop源码,会发现事件的处理主要在kCFRunLoopBeforeSources和kCFRunLoopBeforeWaiting状态之间,以及kCFRunLoopAfterWaiting之后。然后我们就可以监控这两个状态了。如果时间过长,则表示发生了卡顿。阿里百川上图来自阿里百川。如图所示,我们将对冻结次数进行判断。如果数量为1,但时间超过,则为单次耗时冻结。如果数量达到阈值,则证明是连续的短期冻结。当发生卡顿的时候,我们会收集一个当时的栈情况来进行定位。可以使用PLCrashReporter来做,也可以自己开发一个堆栈采集库(参考http://www.jianshu.com/p/7e4c7b94ca36)例如,网上已经有很多开源项目,你可以参考https://github.com/suifengqjn/PerformanceMonitorcrashdetection进行崩溃检测,一般是Mach异常或者Objective-C异常(NSException)引起的。对于这两种情况,我们可以捕捉到对应的Crash事件。Mach异常捕获如果要进行Mach异常捕获,需要注册一个异常端口。这个异常端口将对当前任务的所有线程都有效。如果要针对单线程,可以通过thread_set_exception_ports注册自己的异常端口。当异常发生时,首先将异常抛到线程的异常端口,然后再尝试抛到任务的异常端口。当我们捕获异常时,我们可以做一些我们自己的工作,比如收集当前堆栈。关于如何注册异常端口,这里有原理图和PLCrashReporterhttps://github.com/plausiblelabs/plcrashreporter可以参考Unix信号捕获对于Mach异常,操作系统会转换成对应的Unix信号,所以如果如果你对Mach不熟悉,如果你熟悉的话,你也可以通过注册signalHandler来实现信号异常。例子可以参考https://github.com/xcysuccess/iOSCrashUncaughtsignal(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日志,并上传到后台进行数据分析//registertheuncaughtexceptionhandlerSetUncaughtExceptionHandler(&handler);Abortratedetection目前没有办法直接统计内存过高被杀死的情况,一般是通过exclusionStatistics来计算百分比,原理如下:程序正常启动,设置标志位,程序正常退出,清除程序Crash的标志位,清除程序的标志位因为电量过低无法关机,这个无法直接监测,可以加电量检测辅助判断二次启动,标志位如果存在,则表示Abort一次,上传后台用于阿里百川互动监控统计。对于页面的加载时间来说,这个实现起来还是比较容易的。可以直接通过Runtimehook对应的生命周期方法,比如viewDidLoad、viewWillAppear等,进行用户交互痕迹,比如点击那个按钮,跳转到那个页面。本信息偏向于收集用户行为。我们还自主研发了非埋点SDK,专门用于用户行为数据的采集和分析。核心也是基于hookAOP。想法。具体可以参考我同事的著作《网络监控》。对于成功率、状态码、流量、网络响应时间,我们主要可以使用两种方式来做Hook和对URLConnection、CFNetwork、NSURLSession进行hook。具体的技术可以是methodswizzle或者Proxy、Fishhook等。也可以使用NSURLProtocol拦截网络请求,进而获取流量、响应时间等信息,但是NSURLProtocol有其自身的局限性,比如NSURLProtocol只能拦截NSURLSession,NSURLConnection和UIWebView,但是对于CFNetwork你无能为力。第一种方法可以Hook的方法,可以参考这张图统计HTTP和HTTPS的DNS解析,TCP握手,SSL握手(HTTP除外),首包时间等,比较难,但是因为我们使用的URLConnection、CFNetwork、NSURLSession底层是BSDSocket,所以我们可以尝试在socket上实现效果,类似于通过ViewController的生命周期方法来统计页面加载时间的方法。我们Hooksocket相关方法来做,比如hooksocket连接时的connect方法,获取tcp握手的开始时间,通过hookSSLHandshake方法获取SSLHandshake执行时的SSL握手开始时间等.目前听云已经提供了HTTP的分段时间查询功能。让我们试试intconnect(int,conststructsockaddr*,socklen_t)__DARWIN_ALIAS_C(connect);OSStatusSSLHandshake(SSLContextRefctx)但是对于iOS9Apple增加了ATS的新特性并且要求开发者使用HTTPS,当我在HTTPS网络上请求Hooksocket方法时iOS9和10,一些方法挂钩失败。估计苹果对其进行了加固和加密,导致部分系统方法无法hook,所以无法在iOS9和10上通过.socket获取HTTPS网络的分段时间。不过苹果在iOS10中推出了一个API,可以在iOS10及以上版本收集网络信息。metrics打印结果如下(FetchStart)2017-02-2409:03:06+0000(DomainLookupStart)2017-02-2409:03:06+0000(DomainLookupEnd)2017-02-2409:03:06+0000(ConnectStart)2017-02-2409:03:14+0000(SecureConnectionStart)2017-02-2409:03:14+0000(SecureConnectionEnd)2017-02-2409:03:16+0000(ConnectEnd)2017-02-2409:03:16+0000(请求开始)2017-02-2409:03:16+0000(请求结束)2017-02-2409:03:16+0000(响应开始)2017-02-2409:03:16+0000(响应结束)2017-02-2409:03:16+0000当然,如果大家对各级网络的时间采集有好的规划,希望大家留言告诉我。同时,维度信息、内存等一些基础指标也很容易获取,这里不再赘述。大家可以去蘑菇街的手机全链路追踪保障系统http://t.cn/R5whClL美团外卖移动性能监控系统实现http://t.cn/RIUcX0o微信阅读iOS质量保证与性能监控http://t.cn/RibKdFW网易NeteaseAPMiOSSDK技术实现分享http://t.cn/R5ZyWVt阿里百川MaliAPP监控来了重磅玩家进军APM市场http://t.cn/RfjDrvtAPM最佳实践文章专题合集http://t.cn/RxZQOto手淘:快速运维交付实践亿级用户应用http://t.cn/RibFFYO
