作者:陈明义
部门:同城零售
2.1 性能检测
2.1.1 慢方法&ANR检测
有赞零售的业务复杂度非常高,且由于业务场景的特殊性,有大量的复杂业务逻辑处理都是在移动端上做的,本地存在大量的DB操作、数据同步、复杂计算......,此外收银设备的配置和性能相比于手机有很大的差距,这些都对我们提出了很大的挑战。卡顿问题也是我们面临的主要难题之一,为了解决这个问题,我们首先要解决方法运行效率的问题,找出应用中执行效率不满足要求的方法,通过优化这些处理逻辑,提高方法运行效率,进而提升整体的性能。
总体流程分为四步:
Step1:编译期自动采集需要性能检测的方法。过滤不需要进行检测的方法或类,为每个方法分配一个独立ID(包括二方库及三方库的方法),并生成方法ID与方法签名的映射文件。
Step2:编译期对方法进行插桩。通过插桩的方式对所有需要检测的方法进行插桩,在每个函数的函数体前后会自动插入i和o方法,入参为方法ID,这样就可以很方便的对执行时间进行检测。
Step3:运行期进行性能检测。比如慢方法和ANR的检测是通过记录i和o方法的时间并进行存储,会记录每个方法进入和离开的时间,当执行时间超出我们设定的阈值时,会将方法的信息进行上报,方便后面对数据进行处理。
Step4:收集卡顿现场信息。监听每一帧的变化,卡顿发生时,会有单独的线程去收集堆栈信息以及现场环境信息(包含:设备信息、CPU使用情况、内存、磁盘信息等)。
2.1.2 线程池检测
在Android开发中我们通常会将一些耗时任务放到子线程中进行操作,否则可能会阻塞UI线程,引起ANR、卡顿等问题。而我们的App中就存在大量的异步任务,包括网络请求、本地大量的DB操作、定时轮询等任务,而所有的这些异步任务都在同一个线程池中运行(IO线程池),这样就带来了一个问题:当网络请求比较慢的时候,线程池会快速堆积任务,再加上不断轮询的任务,线程池极易被打满,本地快速的一些异常任务就容易被阻塞住,造成耗时短的任务等待耗时长的任务。
为了解决这个问题,我们需要对线程池进行更细粒度的划分,考虑到我们应用的特性,我们对主线程池的定位改为:为大量、快速的本地任务提供支持,这样我们就需要将一些「耗时长」、「频率高」的任务进行治理,将这些任务分离出我们的主线程池,我们需要监控线程池中的任务,能通过监控的数据挖掘异步任务的优化点,同时为线程池的配置调整提供可度量的指标。
检测的核心在于监听线程池的三个节点:
总体流程如下:
通过上面的方式能逐步分离出「耗时长」、「频率高」的任务,通过对这些任务的优化,最终达到线程池优化的目标。另外由于有了完整的线程池负载情况跟踪以及任务执行时间数据,我们对线程池的健康度也有了可度量的指标,这也为我们做线程池的自动化配置提供了参考依据。
2.2 数据处理
2.2.1 整体流程
(1)方法映射文件记录。应用打包时会自动执行上面的编译期处理流程,生成方法映射文件,并上传到APM Server,然后进行方法映射数据的处理。
(2)性能数据同步。卡顿发生时,会上报相关数据。数据会通过DP(数据平台)进行清洗、计算和统计(比如前一天性能报告统计),然后通过Hive -> DB流程同步到后端应用的DB中。
(3)数据解析。后端应用会对数据中的卡顿堆栈进行解析(把ID解析成方法名)。
(4)数据聚合。解析完后需要对同一方法的数据进行聚合(包含跨版本、跨补丁的数据处理,比如A方法可能在1.0版本ID是11,在1.0补丁1版本的ID是22,在1.1版本的ID是33,需要把他们聚合成一条数据),这样就能准确的知道每个方法的严重程度,每条聚合数据也会记录对应的解决状态。
(5)数据分析&报警。会结合数据平台上计算和统计的结果以及数据聚合后产生的数据,产出日报、周报、告警等信息,为性能变化趋势提供数据化支撑。
通过上面的方式将同一个方法的问题进行聚合,可以跟踪所有问题的解决状态,并能通过数据分析进行性能变化趋势的监控以及问题的报警。
2.2.2 关键节点
(1)数据解析&聚合
由于上传的卡顿信息中只会包含方法的ID,我们需要在后端对这些数据进行解析,将它解析成具体的方法名,然而由于不同版本、不同补丁生成的方法映射文件是不一样的,同一个方法在不同的版本对应的方法ID是不一样的,而我们需要将同一个方法引发的问题进行聚合,这样才能有效的跟踪每个问题的解决状态。而是否是同一个方法的认定标准为:完整类名+方法名,这样就能帮助方法的唯一性。
整体解析&聚合流程如下:
(2)数据清理流程
整个监控平台数据虽然经过重重过滤,但是本身的数据量还是非常大的,任由数据无节制的增长会很容易到达我们处理的瓶颈,且这庞大数据中大部分是无需长时间存储的,我们需要有数据的清理机制,通过清理机制来保证我们数据不至于增长过快:
整体清理流程如下:
三、功能介绍
3.1 问题数据
3.1.1 TOP 问题列表
3.1.2 问题详情
3.2 问题报警
3.3 性能报表
3.3.1 ANR变化趋势
3.3.2 慢方法变化趋势
3.3.3 FPS变化趋势
3.3.4 线程池卡顿次数
四、未来规划
五、结语
通过性能监控的实践以及后续的性能优化,帮助我们更好的解决了性能问题,总结下来它的核心价值在于:
性能监控与性能优化道阻且长,我们也会不断地在这方面进行更多的尝试和努力,为App的稳定运行提供更好的保障,做好性能和稳定性的守门员。