首页 > 编程知识 正文

android性能优化和内存优化面试(应用行为监控Android)

时间:2023-05-04 23:22:03 阅读:86574 作者:328

背景

在移动互联网时代,移动端的业务大部分需要通过App和服务器之间的数据交互来实现,所以大部分App提供的业务功能都需要使用网络请求。 如果网络请求慢或请求失败,导致用户无法顺利使用业务功能,则会对用户的体验产生较大的影响。

此外,EMAS向外部提供的APM迄今为止还不包括网络监视功能。 网络性能监控是移动端性能监控的重要组成部分,为了改善APM的产品功能,进一步满足客户的需求,必须补充这一功能。

“阿里巴巴App应用开发平台EMAS是国内领先的云原生App开发平台(移动App、H5 App应用、小程序、网络APP等)、广泛的云原生技术) Serverless、DevOps、低代码等)为企业、开发者提供一站式APP开发管理服务

问题与挑战

网络性能监控主要包括数据收集和数据上报。 我们希望尽可能收集有用的信息,以帮助客户发现、识别和解决网络性能问题。 我们面临着以下问题和挑战。

首先需要解决的是,在网络请求的过程中,哪个阶段会影响请求性能,如果发现网络性能有问题,用户需要收集哪些数据来发现和解决问题。 安卓主流的网络框架有okhttp2、okhttp3、okhttp4、volley、retrofit、http客户端、系统提供的httpurl连接等,客户可以使用网络请求各阶段的数据收集是离散的,如何将单个请求的各离散的监视数据连接在一起,以免与其他请求的监视数据混淆? 由于脆弱网络环境下的网络请求日志往往更有价值,因此必须尽可能向服务器报告异常的网络请求日志数据。 同时进行网络请求时,上传日志时必须尽量不影响客户的正常工作。

实现方案

网络性能监控在端点的具体实现主要包括两个主要模块。

数据采集数据上报其中数据采集是整个SDK框架的核心。 整体体系结构概述:

访问层:网络监视是高可用性产品的一部分,通过高可用性集成访问方式进行访问。 插件层:高可用性当前的框架通过插件方式整合各业务,实现网络监视器插件集成到APM中,补充APM的网络监视部分。 逻辑级别:主要负责收集控制、数据管理、缓存管理和数据上报。 拦截层:整个网络监控的核心。 为了收集更多的信息,我们选择了使用字节码注入技术实现网络请求监视功能。 针对OkHttp、OkHttp客户端和HttpUrlConnection,分别实施Interceptor,收集不同网络库中网络请求各阶段的数据,然后请求结束另外,通过定制gradle plugin方式,在各网络库中实现Injector和开关,在APP构建阶段用Interceptor将各收集方法注入对应的网络库中字节码的嵌入位置

数据采集

收集哪些数据

首先确定收集的数据范围,一方面有助于及时发现网络请求的性能和异常等情况,另一方面也需要额外的数据来帮助排除问题。 我们收集的数据主要包括四部分:

基础数据。 性能数据。 异常信息。 事件序列数据。 基础数据

请求url :聚合请求。 目标IP地址:支持出口多个IP的客户对IP地址维进行数据分析。 dns解析结果:为了分析是否存在域名侵占问题,请求url的域名解析ip列表。 httpcode :根据httpcode决定请求的状态。 上游流量:包括上游头部和请求主体的整体流量,包括重试和重定向上游流量。 监视上行通信量的开销。 下游流量:包括整个请求的下游标头和车身的总流量,包括重试和重定向的下游流量。 用于监视下行流量的系统开销。 网络库的类型和版本:客户更换网络库或升级网络库的版本时,可以提供前后网络数据的差异。

性能数据

性能数据主要是收集和定位整个网络请求各个阶段的耗时状况

慢请求发生的阶段。下图列举了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网络性能监控已经对外开放,后续我们会根据客户实际需求去逐步完善功能。下一步计划实现的需求包括:

支持HttpUrlConnection、HttpClient等网络库。支持body数据的采集上报,让客户可以感知、定位和解决在网络连通性正常,但服务端下发异常数据导致端上业务出现异常的问题。支持日志数据端上预聚合,降低服务端存储压力。支持socket请求的监控。

作者:wydzc原生应用研发平台EMAS 刘宝文(木睿)

本文为阿里云原创内容,未经允许不得转载。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。