APM(Application Performance Monitoring 应用性能监控)是一个由来以久的概念。从1970年起,应用性能监控从以NASA为首的学术界逐渐走向商业应用。至今已在各类型商业应用中有了成熟的标准。但是2010年谷歌公司发布的Dapper论文中,提出了打通多应用,适用于分布式系统部署,尤其是可用于越来越趋于微服务化的网络应用的前后端应用的“开放式监控体系”(OpenTracing)是一个不同于传统单应用封闭式的性能监控标准。从2016年起,各类型适用于开放式监控体系的APM模块也应运而生,包括了Zipkin、New Relic、DataDog、Hawlukar、SkyWalking等著名的开源项目,适用于Go、Java、C#、Python、Ruby、Javascript等诸多常用语言。开放式监控体系组织(opentracing.io)也随之诞生。在微盟前端,我们也主动拥抱开放式监控体系,主要参考了New Relic和DataDog,制作了适合微盟业务体系的浏览器端、小程序端、和Node.js端的APM模块。
2017年微盟已经存在CAT系统。通过对赋予globalTicket将多个微服务的监控串联起来。当年,我制作了初代RPRM(Runtime Performance Reporting Module运行时性能上报模块)用于记录浏览器端和小程序端请求接口中后端返回的globalTicket,并且将请求开始和结束时间进行上报。这个APM体系是比较先进的,如图所示,非绿色的部分的应用动作基本上有了记录,并且也能够对用户最终的体验有了一个大概的认识。当然,它也是有很大的提高空间的。其中最为明显的就是浏览器小程序本身的运行时性能、函数和资源加载耗时、以及Node.js应用内的各类型性能数据依然是黑盒化的。此外由于这两大部分的详细性能的确实,实际上导致了超过50%以上的应用路径中的性能数据并不能得到记录。而且,微盟采用的APM体系也不是开放式监控体系内的,因此每个应用间的数据指标也有一定独创性,想要串联各类型的性能指标比较繁琐。
由于RPRM诞生时就有较强的前端函数生命周期监控属性,因此它逐渐被用于BI数据上报,也就是“打点”。而随着BI数据上报,以及其它各类型数据上报(例如广告数据)的需求的增加,它的功能也越来越强大。也具备了和主流开源APM包类似或者更完善的监控功能。在2018年,我们团队萌发了制作符合pentracing标准的APM系统的想法。当然这其中还需要解决将Node.js的函数进行监听的调整。经过一番波折,我们从最初将统计数据记录于mongoDB或posgreSQL的方案改变为了将统计数据记录与elasticSearch的方案。这是因为和mongoDB或posgreSQL相比,elasticSearch有更好的搜索性能,而且它具备Kibana,一种开源的数据面板,可以通过图形化的操作实现数据结构的展示和查询。在开发过程中有比较好的参考价值,而且在数据面板开发完成前就可以较为轻松的开始查看数据。
就浏览器端为例,新的APM数据统计方案,觉过去相比,除了有更为完善的标准外,也有了更加完善的统计。它将浏览器从收到用户操作,到最终呈现给用户的每个环节,如DNS请求、建立连接、Node.js路由处理、内部请求、再到最终浏览器的函数执行、页面渲染等等,都做了记录也做到了“端到端”的每个细节和环节首次彻底的打通。也由于RPRM高度兼容BI(如业务埋点),所以它具有和用户行为、商业行为的高度匹配性。传统的APM系统往往只具有检查代码质量、应用健康度等指标、和定位部分错误的能力,但是微盟APM系统具有打通BI系统的潜力。我们不仅能知道用户做了什么,还知道他花了多久做这件事情,并且这件事情牵涉了哪些应用。如果这个行为的耗时比较大,或者失败率比较高,我们应该要怎么去优化这个行为等等。
接下来我们来看一个小例子:
上面的两图表展现了小程序用户登陆接口中发生的具体的动作和耗时。它的第一个动作是通过soa-proxy调用名为gen3rdSessionKeyByCode2SessionV2的java服务,获取了了token。接下来它又通过soa-proxy调用了名为getBy3rdSession的java服务,用之前动作中获取的token获取了sessionKey和openId。然后依次调用了三个用户中心(UC)的服务上报了sessionKey和openId等参数,最终获取了用户的wid等关键数据,完成了登陆的全过程。甚至通过细节数据我们得知了它总共耗时和每个行为的耗时,定位到了其中UC服务的耗时是主要耗时发生于来自上海(121.3997, 31.0456)使用了小程序开发者工具的一个客户端等等。
另一方面比如我们的某台服务器在下午四点三十分左右发生过一次宕机。在这个时间段内出现了大量的请求错误(总计7.78万次)。通过微盟APM系统,我们就可以很好的快速定位到类似问题,并且能够很快的响应去解决它们。同时我们还有在大盘数据总查看低速接口、根据类型和服务查看等功能。这样也对具体的定位和发现问题起到了很大的作用。
如图所示,我们通过微盟APM系统不仅可以看清整体系统的大盘,还可以了解到用户行为耗时下的具体内容和子祥,还有每个子项的链式反应各自的耗时。这就把我们的一整套系统和用户的每个行为都结合到了一起,得知用户每个操作中所触发的所有相关事件和函数,以及它们各自的耗时和成功与否。
鉴于微盟的主要业务是通过小程序实现的,而市面上对于小程序的APM一般功能都比较浅,缺乏对函数、内容真实价值时间的记录,往往只是利用了小程序提供的原生的生命周期作为统计节点,不能真实反馈用户体验。微盟APM系统从小程序Agent开始就做出了几个创新。比如,对于小程序函数的耗时进行了统计,并且对页面加载中所需要通过异步接口请求,再用setData完成页面内容的真实呈现的过程也进行了记录。这样可以在真实的反映用户看到页面内容过程中发生的真实的运行时耗时。比如,上图中,我们发现用户加载微商城小程序页面中耗时最大的一个过程是通过了wx.login登陆,并且将返回的信息换取token的过程(分别是841ms和1109ms)。
这两个加起来接近两秒的时间,占了微信小程序打开时间50%以上的耗时,也成为了我们优化的重点。通过和腾讯云的合作,我们利用了运行时启动时调用云函数的方式,将获取token的速度提高了95%。将微商城小程序的启动时间从原先的3-4秒提高到了1-2秒。
在微站小程序中我们发现了小程序启动过程中高频调用wx.getSystemInfoSync和wx.getStorageSync这两个函数。表面上看这wx.getSystemInfoSync这个函数调用的时间是很短的,只有2ms。这就导致了业务方程序员在分模块开发的过程中会直接调用这个函数。但事实上,高频调用该函数以后,会导致其性能的明显下降,在这个例子中,它的速度降为31ms。加上调用的频率之高。它产生大约1.6秒的无意义启动耗时。
同时,也通过APM系统发现业务方程序员将大量的数据通过异常复杂的数据结构用setData函数对视图层传输数据。导致了setData本身的耗时高达2秒以上。这其实都不是特别困难的优化点,但是在没有完善的APM系统以前,想要发现和确定问题,确实是非常困难的。
我还在微盟APM系统内集成了运行时堆的功能。传统的报错日志收集系统如Sentry,是通过记录用户的行为产生的面包屑来定位问题的上下文的。这样做不仅产生了很多重复的数据上报,也不能做到打通前后端多大十几个模块来定位问题产生的根源。然而微盟APM则可以直接看到整个调用链内的所有动作。
比如在刚才的报错中我们随便查看一个运行时报错,我们可以查看到它报错的本质是由于master_open这个接口出现了异常。而通过查看该接口的链路,我们又可以定位到发生错误的具体后端Java模块。
其它一些功能如广告订单查询系统,可以通过APM系统存在的数据来排查现有业务系统存在或可能存在的一些问题。找到比如支付流程中出现的各类问题,进而起到提高下单转化率,降低广告投放成本等作用。
在未来,我还会进一步完善各个端的SDK,同时也会调试和改进现有APM面板提供链路耗时汇总、各段路由(启动)耗时汇总等功能 。数据的查询方便,也会有更多业务指标,让各团队能够更方便的通过店铺、用户等指标对数据进行归类、查询,也可以有更多BI指标的整合,甚至有可能给客户开放部分数据指标,提供更好的商业数据体验等等。
想问下,APM系统中「微信小程序-Page」这块,这里的四个指标,你们的统计口径是怎么样的?