IM即时通讯开发如何压缩移动网络下APP的流量消耗

目前,国内几大运营商的移动数据业务还都处于按流量计费状态,且超出套餐外的流量收费较为昂贵。 那么,一款 APP 是否消耗过多的流量,在用户体验方面影响就显得比较大。

一年多前,部门内的某安卓版的产品收到用户投诉,从安卓系统的流量统计中查看到该产品消耗的背景流量偏高,背景流量即 APP 在用户无操作时后台运行消耗的流量,主要用于一些推荐和更新等信息的推送,这部分流量对用户是有意义的,但是如果消耗过多而用户没有感知到足够信息的推送,在用户看来就等于是变相的“偷”走了用户的金钱。

我们经过自测,该产品在常驻后台运行时 24 小时消耗流量 600KB 左右,而竞品流量消耗在 150KB 左右,一个月下来也是一笔不小的开销,我们团队对该产品的背景流量进行了认真的分析和优化,经历了 4 个月左右的努力,成功的将 24 小时背景流量降到了 100KB 以下,并且基本功能无删减。优化后的版本上线后为用户节省了大量的流量,也就是替用户省了钱,收到用户的一致好评。

整个流量优化阶段现在回头想来,经历过三个大的阶段:

    首先:我们花了大量的精力研究如何测试流量消耗,如何精确的得到每个功能点消耗了多少流量,因为如果我们不了解现状,根本无法去优化流量;
    其次:我们针对每个功能点,根据其功能逻辑,探讨优化方法,以及从全局来看,这些功能点有无精简的可能,从项目之初的无任何优化经验,到项目结束时总结和固化了众多的流量优化经验,我们成功的将流量降到了理想范围;
    最后:我们思考如何将本次优化的成果持续保持下去,即后续的新增特性不能恶化流量消耗,我们开发并完善了流量自动化监控系统,有力的保障了后续的版本流量不恶化。

项目之初,我们对该产品的流量消耗情况进行了详细的摸底,我们要搞清楚,我们的流量到底消耗在哪了?有没有多余和浪费?这就是本文将来展开的主题:即摸清现状

流量测试方法

首先我们对该产品 24 小时的消耗的背景流量进行测试。那么流量测试都有什么方法呢?首先得搞清楚流量是什么?我们的手机通过运营商的网络访问 Internet,运营商替我们的手机转发数据报文,数据报文的总大小(字节数)即流量,这里的数据报文包含手机上下行的报文。由于数据报文采用 IP 协议传输,运营商计算的流量一般都是包含 IP 头的数据报文大小。

搞清楚了流量的定义之后,那么我们可以思考如何来获取应用消耗的流量。最直接的办法就是在手机上抓包,分析报文的总大小,即为应用消耗的流量;如果手机没有 root,不方便抓包时,可以设置一个代理服务器,手机通过 WiFi,设置为代理服务器方式访问 Internet,在设置的代理服务器上抓包进行流量分析。另外,安卓系统目前也提供了 TCP 流量的统计,如果被测应用使用的是 TCP 协议,则可以直接取该统计值来计算流量。即时通讯聊天软件app开发可以加蔚可云的v:weikeyun24咨询

间接的流量测试方法比如通过第三方流量监控软件来获取流量,还有通过运营商的流量查询方法(短信,营业厅等方法)来获取流量的消耗情况,也都可以达到我们获取流量的目的。

大家在流量测试的过程中,需要根据自身应用的特点,因地制宜的选择最合适方便的测试方法。下面我们详细的介绍两种最常用的流量测试方法:抓包测试法、统计测试法。

测量流量最直接的方法就是抓包。在 APP 运行期间,把手机收发的所有报文都抓取下来,再计算收发报文总大小,即 APP 消耗的流量。但是如果我们需要测试某一个 APP 消耗的流量呢?项目之初,我们想到的方法是通过第三方应用,来禁用其他 APP 的联网权限。下面详细介绍一下这种方法的操作步骤:

【第一步】:限制其他 APP 联网权限

手机上很多 APP 的进程是常驻后台的,即使不运行,也会有网络报文。所以,为了准确的抓取被测应用的报文,需禁止其他应用的联网权限。我们可以通过手机管家类的软件来禁止联网。如图 5-3 所示,为腾讯手机管家对应用联网控制的界面。

【第二步】:手机上抓包

安卓系统上常用的抓包工具是 tcpdump,具体的操作步骤如下:

    PC 上安装 adb,直接下载或者通过 eclipse 中的安卓开发环境自带的工具集获得。

    检查设备连接情况:

    把 tcpdump 拷贝至 /data/local 目录,注意,/data/local 目录需要 root 权限才能拷入,所以先使用 adb push 拷贝至手机 /sdcard 目录,再使用 adb shell 进入命令行,使用 su 进入 root 状态, cp 至 /data/local 目录:

    为 tcpdump 添加可执行权限:

    启动抓包,使用命令 /data/local/tcpdump -p -vv -s 0 -w /sdcard/capture.pcap

    “ Got”后面的数字表示当前抓到的包的数量。如果在变化,表示有网络流量。
    我们刚刚把抓包的结果保存在了 /sdcard 目录下,导出抓包的结果到电脑。

【第三步】:根据抓包文件统计流量

这里需要对抓包文件分析,获得抓取的报文总流量,目前 PC 上的抓包软件 wireshark 就提供这样的统计功能。用 wireshark 打开刚刚的抓包文件,点击 Statistics->Summary,

安卓系统自身提供了 TCP 收发长度的统计功能,一般 APP 和后台服务器之间的通信都是基于 TCP 的,所以我们可以利用此统计来测试我们 APP 的流量,而且安卓提供的该统计功能是按照 APP 纬度来统计,不需要禁止其他 APP 的联网权限。

下面简单的介绍一下操作步骤:

    使用 ps 命令查看所测 APP 的 uid,如下图举例,手机 QQ 的 UID 为 10000 + 155 = 10155(即红框数字 +10000)。
    进入 /proc/uid_stat/10155 目录, cat 获取当前 tcp_snd 和 tcp_rcv 的初始值:
    进行测试一段时间后再次获取 tcp_snd 和 tcp_rcv 的值:
    所测时间内的流量计算:
    发送流量: tcp_snd_new – tcp_snd_old = 418375 – 391582 = 26793 bytes
    接受流量: tcp_rcv_new – tcp_rcv_old = 5902341 – 5840747 = 61594 bytes
了解了流量测试方法,我们就开始着手测试我们产品的流量消耗情况。

在开始测试流量时,我们首先需要搞清楚测试场景,我们需要测试产品的背景流量,在不操作 APP 的情况下,我们的测试时长是多少?为了研究这个问题,我们经过了详细的测试,发现一天中每个时间段的流量都是不一样的,即上午的一小时消耗的流量可能就与下午的一小时消耗的流量不一样。在研究了 APP 的运行机制后,我们发现, APP 后台运行时的流量一般都是按照时间策略触发的,每天的各个时间段的发包频率是不一样的,基于这种机制,我们就需要测试 24 小时 APP 的背景流量。

搞清楚了测试场景之后,摆在我们面前的难题来了,如果每轮测试都需要 24 小时,那我们的测试效率太低了,每次优化后的版本都需要测试 24 小时,我们可能一年也做不完这个项目。所以我们开始着手研究如何提升测试效率。

首先想到的是让系统的时间跑得快一些,比如说实际的一秒钟,我们让系统的时间变化一分钟,这样 24 小时不就变成 24 分钟了吗?我们赶紧验证我们的想法,我们自己写了一个 APP,周期性的改变系统时间,发现这种方法是凑效的,但是相比于正常 24 小时的流量,这种方法测试出来的流量是偏少的,通过日志打印,我们发现这种加速方案对大部分协议是生效的,但是对一部分协议不生效,我们对不生效的协议进行了代码分析,发现这部分协议的发送是采用了相对定时器的机制发送,相对定时器是基于系统 ticks 计数来进行任务调度的,修改系统时间对此不凑效。

我们开始想到的解决办法是在代码中重构相对定时器的函数,例如传入的参数是一小时调度一次,重构后的相对定时器首先会将传入参数除以 60,再传递给系统相对定时器函数,这种办法是凑效的,但是有一个缺点,就是必须单独编译一个版本,不能直接使用发布版本来测试,这也会对我们的测试效率产生影响,后来经过研究,我们想到了 hook 的方式,动态重构发布版本的相对定时器函数,达到了同样的功效。

最后我们将研究成果和方法总结概括一下:

    1) 基于时间点的定时任务采用周期性修改系统时间来加速:
    这种方式在代码实现时是调用了 (AlarmManager)am.set(AlarmManager.RTC_WAKEUP, point, sender) 方法,其中 point 为系统绝对时间,周期性的修改系统时间加速该类定时任务是有效的,这里我们使用 APP 的方式来实现,每隔一秒使系统时间增长一分钟。
    2) 相对定时器任务采用 hook 的方式重构定时器函数:
    相对定时器采用 Handler 的 sendMessageDelayed(msg, long) 方法进行定时调度,该方法是基于系统 ticks 计数来进行任务定时调度的,我们采用 hook 的方式,修改系统的 sendMessageDelayed 函数,将传入的时间除以 60,这样, 1 小时的周期定时器实际为 1 分钟。 Hook 采用 xposed 框架开发。


使用这两种加速方式, 24 分钟即可完成 24 小时的流量测试,大大提升了测试效率。

这种方法也有局限性,比如后台服务器下发的 push 等信息是后台服务器根据自身的时间策略下发的,终端的这种加速对后台是不起作用的,但是,由于 push 的流量占比不是很大,所以在我们的优化中这种影响是可以忽略的。

项目进行到这里我们已经能很快的获得 24 小时 APP 的背景流量了,但是这个流量数值是无法指导我们后续的优化工作的,因为我们不知道从哪个网络功能开始着手分析。所以我们需要搞清楚,我们这些流量消耗都干了什么事情。

首先,我们跟业务开发团队进行了沟通,跟开发人员了解流量现状,我们了解到,我们这款 APP 没有采用长连接,所以服务器上的更新,通知等信息是需要 APP 周期性的向服务器发送查询消息来获取的,不同业务的查询消息的发送频率是不一样的。由于业务开发团队是按照特性( feature)来划分的,各自为营,不同开发小组开发的消息结构和发送机制也都是不统一的,而且有很多消息的发送时机选择得也不是很好,服务器返回的内容很多都不是最精简的,存在冗余,所以导致消耗流量过多。

面对如此杂乱无章的流量消耗,我们需要搞清楚我们的 APP 每条 IP 报文的功能,都干了什么事情,理清楚了这些之后才能进行逻辑上的优化,进而进行流量的优化。下面会详细介绍我们是如何理清楚当前的流量消耗的,如何变无序为有序的。

猜你喜欢

转载自blog.csdn.net/wecloud1314/article/details/125993469