剑客
关注科技互联网

APM从入门到放弃:可用性监控体系和优化手段的剖析

【51CTO.com原创稿件】在《黑客帝国》电影中较为经典的一幕是让Neo在红药丸和蓝药丸中做出选择。红药丸作为一个跟踪程序,帮助Neo定位物理身体位置,无论在哪里,出现任何问题都能够第一时间定位并解决。而开发者基本都知道,想解决大部分的功能性问题的难点基本就在定位上,而电影里面出现的一些人工智能、机器学习、虚拟现实的技术,也只能够在科幻电影中才能看到。也许这部电影的导演沃卓斯基兄弟也不会想到,在电影拍摄完成的18年后,虽然TA们已经成为了沃卓斯基姐妹,但是这部电影构思出来的大部分技术和能力都已经在今天大行其道。

APM从入门到放弃:可用性监控体系和优化手段的剖析

季度活跃设备增长趋势

今天,在移动终端的爆发以及用户需求的推动下,应用的规模相比以往都在急剧扩大,因此导致了在2015年整个移动互联网进入了一个寒冬的季节。这时对于移动开发在朋友来说,真正能切身体会的是用户、数据的增长率都在下降,拿融资也极其困难。而在移动应用的“体量”不断在急速扩大,通过用户越来越关注体验的需求到国内大批暗流涌动的APM厂商,从服务端到APP端再到H5端不断加强监控能力和策略来适应不同的场景需求,使得监控和优化的本质上已经发生了变化,对用户体验和可用性的要求越来越高。

APM的雏形发展

在90年代末,一个互联网还属于发展时期的时代,PC应用因受限于网络的限制,反应速度远远无法满足大家在那个商业起步阶段的捞金热情。在1996年的时候,Tivo与HP公司就从应用程序层面出发,开发了应用响应管理开发包,他们认为网络无疑就是应用的速度。直至后来,互联网随着一些故障、带宽、数据管理等问题的出现,APM雏形才慢慢的建立起来。

1998年的时候,面向商业化管理的APM产品出现,发展到以组件为中心基础建设监控,分别从系统、中间件、数据库等方面监控、这也是APM发展的中期,但是在这段时间里,像IBM、CA、Oracle、HP这些厂商提出的APM概念在整个行业里增长缓慢,每年的增长率不到10%,这里主要的原因是什么呢?因为在早起的APM的重系统,轻交互上,跟飞快发展的IT环境格格不入,主要没有面向用户,而且周期过长,运维人员维护成本较高,易用性非常低,最终没有形成完整的标准化产品。

从2007年开始,整个无线互联网刚刚起来,很多企业在性能优化上更多专注自己的PC端业务,真正关注移动性能优化是在2011-2012年,移动设备的普及,APP应用市场的爆发,开启了全新的移动访问方式。大家在生活、娱乐、社交等都离不开移动应用,而对于性能体验的要求也越来越苛刻。此时,国外的APM行业New Relic和AppDynamics已经在APM领域拔得头筹,国内一些APM厂商看准移动的这个趋势,APM仿佛一夜之间遍地开花,直至今日,作为国内比较具有代表性的APM厂商,比如:阿里百川的码力、听云等都是非常成熟的本土APM厂商。开发者无需从零开始构建性能探针、数据平台和控制台,就可以通过可视化、可运维的方式长期监控应用性能、及时解决应用中存在的问题。

APM从入门到放弃:可用性监控体系和优化手段的剖析

常见的APM厂商提供的解决方案

APM可用性度量体系

如今,很多人会发现在APM业务竞争慢慢削弱后,体验的竞争又开始了。比如在微信出来的时候,大家都觉得在移动方面的体验会比手Q好很多,这不仅是关系一个开发工程师的水平,更是在于一套度量的体系,这是非常关键的。阿里技术专家陈武认为,在性能优化方面,以往的度量是通过APP的打开率来进行对比,很多都是非常主观。但是度量体系里面面临的一个很大的问题是常态化。接着,陈武举例说明,开发团队在发布下一个APP版本的时候很难做到沉淀,比如沉淀文档、沉淀经验。对于适应整个激烈的竞争市场,很难做到敏捷。那么,在可用性上,我们应该如何建立起这一套度量的体系呢?

1、可用性度量

1)可量化、可视化。通过对于版本的对比,开发者或者运维人员通过曲线能够直观的了解到APP每次发版时候的问题修复情况,通过沉淀来保障整个项目的实时交互。

2)服务的可用性。对于可用性的优化非常关键,能够第一时间去感知和处理问题。

3)网络的可用性。在移动互联网的场景,由于地域的原因,如果出现运营商劫持,服务端是无法感知到,只能通过移动性能监控才能了解哪个地域出现问题。

在移动互联网的可用性方面,如果在可用性上没有及时感知,有可能会导致公司直接倒闭的危险。

2、体验度量

体验是一个APP对用户留存的关键。大家对APP使用过程中“如丝般顺滑”都具有天然的好感。但是目前市场上还有很多APP的体验非常差,从卡顿、闪退、耗电、延迟到因为非常占内存的原因被系统关掉。这个时候,非常需要有一个系统去陈列和度量。

在性能优化的量化过程如何帮助企业去做定制?陈武认为,一条关键的路径所有的URL整合在一起,是非常重要的健康度指标。比如通过网络监控,开发者无需对所有的URL都需要关注,可能不同的开发者关注的业务不同,大家关注的URL不一样。在通过电商的场景,一个关键的路径是用户通过登录,打开商品,进入详情,然后下单到支付,这是一条非常关键的路径,通过把对应的关键路径所有的URL整合在一起,才能够强化业务的稳定性。

APM的可用性检测方式

APM从入门到放弃:可用性监控体系和优化手段的剖析

▲ 阿里百川APM的监控体系

对于加强应用的可用性,APM一般都采取应用监控结合服务监控的形式,使得开发者实现端到端的全链路性能管理。在阿里百川APM监控体系中,阿里巴巴技术专家熊奇介绍了阿里百川码力在监控体系里面的应用监控、服务监控、数据库以及消息推送等性能监控,主要通过以下方式来完成:

  • 在应用监控上,采集了iOS、Android应用的内存、CPU、崩溃、网络等方面的性能数据;
  • 在服务监控上,支持Tomcat、Jetty、JBoss容器和Spring、Struts等框架的性能检测;
  • 支持MySQL等SQL数据库和Redis、Mem cache等NoSQL数据库的性能检测;
  • 阿里百川码力还提供了支持淘宝消息服务TMC、分布式框架Dubbo、淘宝API调用的性能检测。

对于数据采集之后会统一进入可以承载海量数据的存储系统和日志系统,统计系统会利用落地的数据完成数据的计算处理、生成报表,帮助开发者长期跟踪应用和服务的性能,

而告警系统则会根据规则在问题发生时发出短信、邮件等即时告警,从而帮助开发者及时解决问题,降低损失。

可用性的度量检测方式-性能

APM从入门到放弃:可用性监控体系和优化手段的剖析

在应用开发时,程序错误、主线程卡顿和资源使用超过系统限制导致的崩溃,是最严重、也是需要首先解决的问题。

通常开发者会借助模拟器、Instrument或者自动化测试发现一部分问题,但是测试往往难以覆盖用户使用场景下的设备、网络等环境。如果借助于社交媒体或者邮件反馈渠道,虽然可以有限的拿到真实的用户反馈,但是用户往往不能清楚的描述出复现问题所需的信息,往复沟通成本极高。所以,在客户端上,我们通过以下检测方式来收集应用崩溃信息。

APM从入门到放弃:可用性监控体系和优化手段的剖析

码力在信号捕获方式中,通过sigaction设置信号中断时的回调,这样,就可以在回调中根据程序运行状态生成对应的崩溃日志。此外,对于SIGARBT(abnormal termination),我们还需要通过NSSetUncaughtExceptionHandler来获取未捕获异常的堆栈,来补全崩溃信息。

而后,把崩溃日志上报到码力,会依据崩溃日志的堆栈信息,聚合同一类型的崩溃后写入数据存储。同时,告警系统可以依据崩溃次数、崩溃率等规则,即时发出告警。

此外,码力提供了dSYM上报脚本,在Xcode的build phrase中添加脚本,就可以在编译成功后自动上报dSYM文件到码力。我们会解析dSYM文件,重新聚合后写入数据存储,聚合可以减少高达90%数据库行数;同时,我们还实现了崩溃日志符号化服务。我们应该是第一家不依赖mac环境符号化的公司,因而我们可以更好的利用我们的云计算平台,来服务更多开发者。

APM从入门到放弃:可用性监控体系和优化手段的剖析

第二种技术是卡顿检测,卡顿检测的基础是RunLoop,我们通过RunLoop Observer监听主线程RunLoop状态的变更。在这里,我们把RunLoop当作在操场上跑圈的运动员,把Before Sources当做每圈的起点,同时另外开启一条线程作为计时员,每5秒判断一次RunLoop是否跑过一圈。如果5秒内RunLoop没有完成一次RunLoop,则视为主线程卡顿。在发现主线程卡顿后,我们会生成卡顿日志,如果是复现的卡顿,我们可以选择不重复上报。

此外,针对设备不同的运行时期,如启动阶段、后台阶段、空闲阶段,我们会动态调整阈值,降低检测的开销。

APM从入门到放弃:可用性监控体系和优化手段的剖析

对于无法通过信号捕获、卡顿检测的崩溃,我们引入了应用中止检测,中止检测虽然不能还原崩溃现场,但是可以揭示问题的存在。在应用进入active状态时,我们在持久存储上设立一个标志位,表示程序在正常运行。在应用退出active状态或检测到崩溃时,我们清除持久存储上的标志位,表示程序在已知的情况下退出。这样,在下一次应用启动时,如果持久存储上的标志位为真,则说明应用上一次运行在未知情况下退出,这种情况我们就计为应用非正常中止上报。

同时,为了过滤因为电量耗尽导致的关机,我们还增加了电量检测,在低电量时,清除标志位,避免中止误报。

可用性的度量检测方式-网络

APM从入门到放弃:可用性监控体系和优化手段的剖析

请求错误、流量开销高、被运营商劫持等网络问题是应用开发时另一类棘手的问题。当然我们也可以借助模拟器、Instrument或者自动化测试发现简单的网络问题,但是测试难以覆盖复杂的用户网络环境,也难以导出网络性能数据进行长期比对监控。如果使用手工埋点的方式记录网络性能,一方面,我们需要应对多种系统网络接口,另一方面,我们需要同步应用网络代码和埋点代码,维护成本将会居高不下。

为了监控应用在真实网络环境中的性能,码力APM中引入了无痕埋点的网络性能监控,在网络检测中引入三种注入技术,帮助开发者长期监控应用的网络性能,优化产品用户体验。

APM从入门到放弃:可用性监控体系和优化手段的剖析

第一种是Method Swizzling。

  • 每一个NSObject类都包含一个isa指针,指向objc_class结构体;
  • 每一个objc_class结构体又包含一个methodLists指针,指向objc_method_list结构体数组;
  • 每一个objc_method_list又包含一个objc_method结构体成员;
  • 每一个objc_method包含一个method_imp指针,指向方法实现。

因此,只要能修改method_imp的值,我们就能替换原有的实现。在<objc/runtime>中,通过class_getClassMethod和class_getInstanceMethod取得objc_method结构体指针,而后通过method_getImplementation取得方法的原始实现地址originIMP,之后在imp_implementationWithBlock生成新实现imp的参数block里,调用原始实现,就可以原有行为前后加入网络性能埋点行为。最后调用method_setImplementation替换方法实现。这样,任何调用都将使用新的实现。

APM从入门到放弃:可用性监控体系和优化手段的剖析

第二种技术是Proxy。在Objective-C里,NSProxy是除NSObject外唯一的根类。NSProxy是一个实现了NSObject协议的抽象类,它的正常运作需要子类override -methodSignatureForSelector:方法为sel提供方法签名,以及-forwardInvocation:方法来完成调用的转发。

使用Proxy来注入NSURLConnection、NSURLSession等对delegate的回调。具体来说,在delegate proxy收到消息时,如果不是目标协议方法,则通过消息转发机制,转发给原delegate;如果是目标协议方法,则直接调用proxy实现,在proxy实现中委托调用原delegate;此外,多数协议和协议方法都是可选的,因此,在proxy的实现中需要实现-conformsToProtocol:和-respondsToSelector:方法来声明proxy额外加入的协议和方法。这样,我们就能在不影响原有回调的同时,增加网络性能埋点逻辑。

APM从入门到放弃:可用性监控体系和优化手段的剖析

第三种技术是fishhook。使用fishhook来替换动态链接库中的C函数实现,具体来说是CFNetwork和CoreFoundation中的相关函数。这里,以开车的模型来解释动态链接。设想一名新手司机开车从巴黎到罗马,因为他不知道路线,于是他先去咨询老司机;老司机告诉他正确的线路,这一次他可能还会绕点路,但下一次,他就会按照老司机的建议直接开到罗马。

相应的,在程序运行时,动态链接的C函数dynamic(…)地址记录在__DATA segment下的__la_symbol_ptr中;初始时,程序只知道dynamic函数的符号名而不知道函数的实现地址;首次调用时,程序通过__TEXT segment中的__stub_helper取得绑定信息,通过dyld_stub_binder来更新__la_symbol_ptr中的符号实现地址;这样,再次调用时,就可以通过__la_symbol_ptr直接找到dynamic函数的实现;如果我们需要替换dynamic函数的实现,只需要修改__la_symbol_ptr即可。具体的实现方式,可以参阅Facebook的开源框架fishhook。

加强可用性的优化手段

通过以上两种检测方式,基本能够大部分的性能和网络需求,使得开发者能够满足如今移动互联网下用户的苛刻的需求,那么,建立起来的度量体系后,了解的具体的问题后,我们应该如何去解决这些问题来提升可用性呢?

1、运营商、DNS劫持

运营商、DNS被劫持问题是应用开发时一类棘手的问题, 解决方案也比较多。51信用卡技术总监汪睿认为,51信用卡作为金融属性的产品,基于安全考虑会放在第一位。解决方案主要是基于全栈HTTPS的方案来处理,但会带来一些成本和性能上的损耗。甚至可以像FaceBook、google等一些解决方案,使用HTTP2.0方式,这取决于公司和开发者自身去评估实现的成本。汪睿还介绍了早起的一个过渡方案,那就是HTTP的DNS方式,通过获取一个IP表通过IP来直接连接,可以避免HTTP劫持的问题。

对于DNS被劫持的问题,阿里技术专家陈武认为,如果在链路没有问题的情况下,那么必须在整个网络传输层要尽量快,不然很容易出现out。所以,第一要从协议层,在协议层里面通过http2.0来减少包头的压缩,同时支持服务端push消息,且通过双通通道,对通道复用更快。第二是从数据层,数据可以通过二进制压缩。在整个网络连通率较低的时候,将打包拆成小包,达到很好的传输效果。

2、系统降级

降级的解决方案,是系统性能保障的最后一道防线,从性能优化的角度上说,没有100%完善的设计,总会有一些意料突发的情况导致性能恶化。所以,在系统设计时,必须做好降级设计。

饿了么移动首席架构师王朝成认为,在饿了么517大促活动上,服务器端承受非常大的压力,这个时候会通过降级部分服务的方式,来确保大促秒杀这种场景得以正常运行。但是,在用户端上,以及APP,还在不断积极的发送用户请求和数据,反而增加服务器集群的压力。这个时候,王朝成表示,他们会考虑把一部分的SDK或者APP上的服务也进行降级,来减少服务端在分析数据上的压力。

降级分为手动降级和智能降级,在策略上分为流量降级、效果降级、功能性降级。流量降级主要表现在通过主动拒绝处理部分流量早餐部分用户服务不可用。而效果降级和功能性降级都表现为服务质量的降级,一个是通过在流量高峰时期用相对低质量、低延时的服务来保障所有用户的服务可用性,另外一个是通过减少功能的方式来提高用户的服务可用性。

3、优化数据流量

从数据结构上,需要根据不同的业务场景来选择合适的数据结构,在数据流量较少的情况可能客户端上表现不出什么区别,当在数据流量过大,且数据结构复杂的时候很可能就是直接影响到APP的性能。

类似餐饮领域“饿了么”这样的应用,数据发送的频率使得据量会非常大,对用户来说可能没有什么感知,但是商家接收大量的订单,数据量影响很大,感知比较明显。王朝成认为,可以考虑一些新的协议(Protobuf, Flatbuf)来优化数据量,比如HTTP2.0可以压缩http协议的header,使用encoder来减少需要传输的header大小,通过通讯双方各自cache一份header fields表,对于相同的数据不再通过每次请求和响应发送,又减少了需要传输的大小。

再一个是采取二进制的协议,只认0和1的组合,通过把原来http1.x的header和body部分用frame重新封装,实现方便且健壮。通过内容压缩与并发传输机制,在低速、不稳定的无线条件下,较少其http body的发送大小,改善用户体验和资源效率。

APM从入门到放弃:可用性监控体系和优化手段的剖析

▲ http1.x和http2.0协议关系

4、动态热修复

所谓热修复,就是使用热补丁动态修复技术,通过向用户发送Patch,在用户无感知的情况下完成一些致命bug的修复。51信用卡客户端负责人汪睿认为,在移动客户端上最大的一个问题是发版,对于iOS的用户来说,整个修复流程比较漫长。需要提交审核,但是在这段时间有可能已经错过很多用户。他认为,热修复技术能够很快并及时的在线进行修复,通常在使用的过程中就完成的修复过程。

在热修复技术上,Android常用的是基于Android dex分包方案,而iOS可以利用JSPatch,它可以使得你用JavaScript书写原生iOS APP,只需要在项目中引入极小的引擎,就可以用JavaScript调用任何的Objective-C的原生接口。

总结

以上所谈到的性能优化手段基本是为了解决三种情况所造成的问题:1. 日渐复杂的业务导致功能不断迭代所突发的致命bug修复方式,2. 日益增长的用户和膨胀的数据导致流量过大,3.网络安全和内存开销的问题。

本文通过不同的场景来分析移动性能优化的模式,可以通过确定场景下解决某一类型的问题。当然,我们不能仅仅通过了解性能优化所解决的问题以及手段,更重要的是需要清楚该问题所发生的场景、原因需要的成本。

【51CTO原创稿件,合作站点转载请注明原文作者和出处为51CTO.com】

【责任编辑:林师授 TEL:(010)68476606】

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址