背景
挪动互联网时代,挪动端极大局部业务都须要通过App和Server之间的数据交互来实现,所以大部分App提供的业务性能都须要应用网络申请。如果因为网络申请慢或者申请失败,导致用户无奈顺畅的应用业务性能,会对用户体验造成极大影响。
此外,EMAS对外提供的APM之前并不包含网络监控性能,而网络性能监控作为挪动端性能监控的重要组成部分,咱们急需补全这部分能力来欠缺APM的产品性能,进一步满足客户的需要。
“阿里巴巴利用研发平台 EMAS 是国内当先的云原生利用研发平台(挪动App、H5利用、小程序、Web利用等),基于宽泛的云原生技术(Backend as a Service、Serverless、DevOps、低代码等),致力于为企业、开发者提供一站式的利用研发治理服务,涵盖开发、测试、运维、经营等利用全生命周期。”
问题与挑战
网络性能监控在端上次要包含数据采集和数据上报。咱们心愿能尽可能采集有用的信息来帮忙客户发现、定位和解决网络性能问题。咱们面临如下问题和挑战:
- 首先要解决的是网络申请过程中,哪些阶段会影响申请性能,如果发现网络性能有问题,须要采集哪些数据来帮忙用户去定位和解决问题。
- android上支流的网络框架有okhttp2、okhttp3、okhttp4、volley、retrofit、httpclient和零碎提供的httpurlconnection等,在咱们不确定客户应用哪个网络库的哪个版本的状况下,如何尽量采集有用的信息。
- 网络申请各个阶段的数据采集都是离散的,如何保障单个申请各个离散的监控数据可能串联起来,不和其余申请的监控数据混在一起。
- 因为弱网环境下的网络申请日志往往更有价值,须要尽可能将异样的网络申请日志数据上报到服务端。
- 并发网络申请时,须要确保在日志上传时尽量不影响客户失常业务。
实现计划
网络性能监控在端上的具体实现次要蕴含两大模块:
- 数据采集
- 数据上报
其中数据采集是整个SDK框架的外围。
整体架构概览:
接入层:
网络监控属于高可用产品的一部分,采纳高可用对立接入的形式接入。
插件层:
高可用目前框架是通过插件式的形式集成各个业务,实现networkmonitor plugin集成到APM中,补充APM中网络监控局部。
逻辑层:
次要负责采集管制、数据管理、缓存治理和数据上报。
拦截器层:
整个网络监控的外围。为了采集更多的信息,咱们抉择应用字节码注入技术来实现网络申请监控性能。对OkHttp、HttpClient和HttpUrlConnection,别离实现Interceptor去采集不同网络库中网络申请各个阶段的数据,并在申请完结时实现采集进行上报。此外,通过自定义gradle plugin的形式,为各个网络库实现Injector和开关,管制在利用构建阶段将Interceptor中各个采集的办法注入到对应网络库字节码的埋点地位,从而实现在运行时网络申请各个阶段采集须要的数据。
数据采集
采集哪些数据
首先须要确定采集的数据范畴来帮忙咱们及时发现网络申请的性能和异样等状况,另一方面也须要有额定的数据来辅助排查问题。所以咱们采集的数据次要包含四个局部:
- 根底数据。
- 性能数据。
- 异样信息。
- 事件序列数据。
根底数据
- 申请url:对申请做聚合运算。
- 指标IP地址:对于多进口IP的客户,反对IP地址维度的数据分析。
- dns解析后果:申请url的域名解析ip列表,用于剖析是否存在域名劫持的问题。
- http code:依据http code确定申请状态。
- 上行流量:包含整个申请上行header和body的总的流量,蕴含重试和重定向的上行流量。用于监控上行流量开销。
- 上行流量:包含整个申请上行header和body的总的流量,蕴含重试和重定向的上行流量。用于监控上行流量开销。
- 网络库类型及版本:对于客户更换网络库或者降级网络库版本的状况,能够提供前后的网络数据的差别。
性能数据
性能数据次要是采集整个网络申请中各个阶段的耗时状况来定位慢申请产生的阶段。下图列举了http申请可能呈现的各个阶段。
所以性能数据局部须要采集下述各个阶段的耗时数据:
•整个网络申请耗时
• •dns耗时
• •建连耗时
• • •TLS建连耗时
• •数据上行耗时
• • •header上行耗时
• • •body上行耗时
• •数据上行耗时
• • •header上行耗时
• • •body上行耗时
异样信息
异样信息次要是收集网络申请各阶段出现异常时的异样栈的信息。比方常见的java.net.UnknownHostException、java.net.SocketTimeoutException等。
事件序列数据
事件序列数据次要是收集网络申请各阶段的监控事件的信息,另外对于特定网络库的一些非凡的事件的监控,比方okhttp的连贯复用、主动重定向和失败重试等对网络耗时有影响的机制。最初将这些事件按工夫顺序排列。
比方在okhttp上dns被劫持的场景,咱们通过根底数据中的指标IP地址去判断dns劫持状况,这个指标IP地址是在建设连贯的时候去采集的。如果第一个申请产生了dns劫持的状况,那这个申请咱们能失常辨认的dns劫持曾经产生。如果后续的网络申请复用了这个连贯,因为不会再去建设连贯,所以根底数据中没有指标IP地址,这时候就须要应用事件序列数据中的连贯复用事件中的连贯的url和指标IP地址来判断是不是被劫持的申请。
如何采集数据
字节码插桩原理
字节码插桩波及到Android的打包构建流程。首先咱们看下Android应用程序的打包流程,如下图:
从上图可知,咱们只须要在 javac 之后 dex 之前遍历所有的字节码文件,并依照肯定的规定过滤批改就能够实现字节码的插桩。
从Android Gradle 1.5.0 开始,Google官网提供了Transform API。通过Transform API,容许第三方以插件的模式,在Android应用程序打包成dex文件之前的编译过程中操作.class文件。
Android编译器中的TaskManager将每个Transform串起来,第一个Transform接管来自javac编译的后果,以及曾经拉取到本地的第三方sdk(jar、aar),还有resource资源。这些编译的两头产物,在Transform组成的链条上流动,每个Transform节点能够对class进行解决再传递给下一个Transform。常见的混同、Desugar等的实现就是封装在一个个Transform中。而自定义的Tranform会插入到这个Transform链条的最后面,所以开启混同的状况下通过自定义Transform对字节码进行批改也是先批改字节码再混同。
网络库调研
除了零碎自带的网络库HttpUrlConnection,在android平台还有很多优良的第三方网络库,大部分App开发会应用第三方的网络库来发动网络申请。
从上表中支流网络库的底层实现来看,咱们只有反对OkHttp、HttpUrlConnection和HttpClinet的数据采集就能满足支流网络库的性能监控需要。
咱们对利用市场上Top1000的App进行了剖析,按集成数量排序顺次是okhttp3&okhttp4、volley(HttpUrlConnection)、okhttp2和httpclient。其中okhttp网络库占比将近80%,所以咱们优先实现了okhttp网络库的监控实现。
okhttp网络库的监控实现
okhttp网络库家族次要包含okhttp2、okhttp3和okhttp4。其中okhttp3版本散布泛滥,底层实现变动也最多,而okhttp2的底层实现和okhttp3的晚期版本相近,okhttp4是okhttp3的kotlin版本的实现。所以咱们次要介绍下okhttp3上的监控实现。
上图是okhttp3.12.0版本的实现框架,咱们在网络库的具体逻辑里注入代码来采集须要的数据。
okhttp3版本泛滥,从3.0.0-3.14.9曾经有超过40个版本,对于每一个代码注入的地位都须要确保再各个版本上能失常工作。所以实现okhttp3的无痕埋点,版本适配须要消耗大量的工作。
数据上报
数据上报,除了须要思考加密、鉴权、压缩等方面,还须要能确保尽可能少的失落日志,同时还须要管制资源的占用来升高对下层业务的影响。具体实现次要包含两方面:
- 缓存:反对内存缓存和磁盘缓存两级缓存。须要实现业务隔离,多个业务应用缓存性能时能够做到互不影响。
- 上报:因为APM产生的日志较多,为了管制并发数和内存,咱们应用了一个业务共享的线程池和调度队列。调度队列最多缓存10条批量日志,如果超出10条会立刻将日志放入磁盘缓存。另外在上报前提供了日志预处理的凋谢接口不便业务层对日志做解决,比方抽样、聚合等性能。
后续打算
EMAS网络性能监控曾经对外开放,产品详情:https://www.aliyun.com/product/emascrash/apm,后续咱们会依据客户理论需要去逐步完善性能。下一步打算实现的需要包含:
- 反对HttpUrlConnection、HttpClient等网络库。
- 反对body数据的采集上报,让客户能够感知、定位和解决在网络连通性失常,但服务端下发异样数据导致端上业务出现异常的问题。
- 反对日志数据端上预聚合,升高服务端存储压力。
- 反对socket申请的监控。
欢送大家踊跃留言,提出你们的宝贵意见和倡议,非常感谢!钉钉搜寻35248489,退出阿里云云原生利用研发平台EMAS技术交换群,探讨最新最热门的利用研发技术和实际。