导读:在移动应用开发中,应用上线了只是一个开始,噩梦在后面:手机越用越卡为哪般?手机发烫是为何?谁偷走了用户的钱包?如何瘦成一道闪电?这些问题解决起来都是非常麻烦的,腾讯移动品质中心(TMQ)成立了专项测试团队来解决这些问题。
最近几年,我们针对 Apps 的网络性能优化工作并不多,但每一次都是投入人手较多、时间跨度较长的大任务。本文将给读者们一个一年多以前为公司的某产品成功优化网络流量的案例。速度、成功率与流量正好是 Apps 网络优化的几大重点,希望本文我们分享的思路能够给诸位正在开展或将来会开展此类工作的读者们一些启发。
在上文手机QQ上传速度提升8倍秘诀:解决速度与成功率的“鱼翅”项目 中,我们重点讲解了提升上传速度和成功率的“鱼翅”项目,分析了在移动网络下影响上传速度和成功率的因素,一次次的调优算法并验证,最终提炼出了能应对网络质量瞬息万变的鱼翅算法。而本文则是讲解了我们在不删减功能的前提下是如何提升某产品待机流量的,重点讲解了流量测试的基本方法,流量自动化测试的经验以及提炼出的流量优化的通用方法。
目前,国内几大运营商的移动数据业务还都处于按流量计费状态,且超出套餐外的流量收费较为昂贵。 那么,一款 APP 是否消耗过多的流量,在用户体验方面影响就显得比较大。
一年多前,部门内的某安卓版的产品收到用户投诉,从安卓系统的流量统计中查看到该产品消耗的背景流量偏高,背景流量即 APP 在用户无操作时后台运行消耗的流量,主要用于一些推荐和更新等信息的推送,这部分流量对用户是有意义的,但是如果消耗过多而用户没有感知到足够信息的推送,在用户看来就等于是变相的“偷”走了用户的金钱。
我们经过自测,该产品在常驻后台运行时 24 小时消耗流量 600KB 左右,而竞品流量消耗在 150KB 左右,一个月下来也是一笔不小的开销,我们团队对该产品的背景流量进行了认真的分析和优化,经历了 4 个月左右的努力,成功的将 24 小时背景流量降到了 100KB 以下,并且基本功能无删减。优化后的版本上线后为用户节省了大量的流量,也就是替用户省了钱,收到用户的一致好评。
整个流量优化阶段现在回头想来,经历过三个大的阶段。
首先,我们花了大量的精力研究如何测试流量消耗,如何精确的得到每个功能点消耗了多少流量,因为如果我们不了解现状,根本无法去优化流量;
其次,我们针对每个功能点,根据其功能逻辑,探讨优化方法,以及从全局来看,这些功能点有无精简的可能,从项目之初的无任何优化经验,到项目结束时总结和固化了众多的流量优化经验,我们成功的将流量降到了理想范围;
最后,我们思考如何将本次优化的成果持续保持下去,即后续的新增特性不能恶化流量消耗,我们开发并完善了流量自动化监控系统,有力的保障了后续的版本流量不恶化。
下面我们就按照项目的三个阶段来详细的分享优化过程中积累的经验和方法。
一、摸清现状
项目之初,我们对该产品的流量消耗情况进行了详细的摸底,我们要搞清楚,我们的流量到底消耗在哪了?有没有多余和浪费?
1、流量测试方法
首先我们对该产品 24 小时的消耗的背景流量进行测试。那么流量测试都有什么方法呢?首先得搞清楚流量是什么?我们的手机通过运营商的网络访问 Internet,运营商替我们的手机转发数据报文,数据报文的总大小(字节数)即流量,这里的数据报文包含手机上下行的报文。由于数据报文采用 IP 协议传输,运营商计算的流量一般都是包含 IP 头的数据报文大小。
搞清楚了流量的定义之后,那么我们可以思考如何来获取应用消耗的流量。最直接的办法就是在手机上抓包,分析报文的总大小,即为应用消耗的流量;如果手机没有 root,不方便抓包时,可以设置一个代理服务器,手机通过 WiFi,设置为代理服务器方式访问 Internet,在设置的代理服务器上抓包进行流量分析。另外,安卓系统目前也提供了 TCP 流量的统计,如果被测应用使用的是 TCP 协议,则可以直接取该统计值来计算流量。
间接的流量测试方法比如通过第三方流量监控软件来获取流量,还有通过运营商的流量查询方法(短信,营业厅等方法)来获取流量的消耗情况,也都可以达到我们获取流量的目的。
大家在流量测试的过程中,需要根据自身应用的特点,因地制宜的选择最合适方便的测试方法。下面我们详细的介绍两种最常用的流量测试方法:抓包测试法、统计测试法。
1) 抓包测试法
测量流量最直接的方法就是抓包。在 APP 运行期间,把手机收发的所有报文都抓取下来,再计算收发报文总大小,即 APP 消耗的流量。但是如果我们需要测试某一个 APP 消耗的流量呢?项目之初,我们想到的方法是通过第三方应用,来禁用其他 APP 的联网权限。下面详细介绍一下这种方法的操作步骤:
第一步:限制其他 APP 联网权限
手机上很多 APP 的进程是常驻后台的,即使不运行,也会有网络报文。所以,为了准确的抓取被测应用的报文,需禁止其他应用的联网权限。我们可以通过手机管家类的软件来禁止联网。如图 5-3 所示,为腾讯手机管家对应用联网控制的界面。
图 手机管家禁止联网示意
第二步:手机上抓包
安卓系统上常用的抓包工具是 tcpdump,具体的操作步骤如下:
1) PC 上安装 adb,直接下载或者通过 eclipse 中的安卓开发环境自带的工具集获得。
2) 下载 tcpdump: http://www.strazzere.com/Android/tcpdump
3) 检查设备连接情况。
4) 把 tcpdump 拷贝至 /data/local 目录,注意,/data/local 目录需要 root 权限才能拷入,所以先使用 adb push 拷贝至手机 /sdcard 目录,再使用 adb shell 进入命令行,使用 su 进入 root 状态, cp 至 /data/local 目录。
5) 为 tcpdump 添加可执行权限
6) 启动抓包,使用命令 /data/local/tcpdump -p -vv -s 0 -w /sdcard/capture.pcap
“ Got”后面的数字表示当前抓到的包的数量。如果在变化,表示有网络流量。
7) 我们刚刚把抓包的结果保存在了 /sdcard 目录下,导出抓包的结果到电脑。
大家看了这么多步骤是不是觉得很复杂,不过不要紧,我们自研的 GT 工具已经把 tcpdump 抓包功能集成进去了,后面介绍 GT 的章节里面会详细介绍抓包方法,在手机上有用户操作界面可以实现一键式抓包,另外 GT 也提供了命令行方式的接口启动抓包,启动命令为:
adb shell am broadcast – a com.tencent.wstt.gt.plugin.tcpdump.startTest – es filepath “/sdcard/GT/Tcpdump/Capture/test.pcap”
停止抓包命令为:
adb shell am broadcast -a com.tencent.wstt.gt.plugin.tcpdump.endTest
后面可以看到,命令行方式可以方便的做进自动化测试脚本中。
第三步:根据抓包文件统计流量
这里需要对抓包文件分析,获得抓取的报文总流量,目前 PC 上的抓包软件 wireshark 就提供这样的统计功能。用 wireshark 打开刚刚的抓包文件,点击 Statistics->Summary,如图 5-4 所示。
流量的数值为 Bytes 一行的 Displayed 一栏。如图 5-5 所示。
图 wireshark 流量统计详细页
2)统计测试法
安卓系统自身提供了 TCP 收发长度的统计功能,一般 APP 和后台服务器之间的通信都是基于 TCP 的,所以我们可以利用此统计来测试我们 APP 的流量,而且安卓提供的该统计功能是按照 APP 纬度来统计,不需要禁止其他 APP 的联网权限。
下面简单的介绍一下操作步骤:
1) 使用 ps 命令查看所测 APP 的 uid,如下图举例,手机 QQ 的 UID 为 10000 + 155 = 10155(即红框数字 +10000)。
2) 进入 /proc/uid_stat/10155 目录, cat 获取当前 tcp_snd 和 tcp_rcv 的初始值。
3) 进行测试一段时间后再次获取 tcp_snd 和 tcp_rcv 的值。
4) 所测时间内的流量计算。
发送流量: tcp_snd_new – tcp_snd_old = 418375 – 391582 = 26793 bytes
接受流量: tcp_rcv_new – tcp_rcv_old = 5902341 – 5840747 = 61594 bytes
了解了流量测试方法,我们就开始着手测试我们产品的流量消耗情况。
2、每天 24 小时待机测试的加速
在开始测试流量时,我们首先需要搞清楚测试场景,我们需要测试产品的背景流量,在不操作 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 的流量占比不是很大,所以在我们的优化中这种影响是可以忽略的。
3、流量精细化监控
项目进行到这里我们已经能很快的获得 24 小时 APP 的背景流量了,但是这个流量数值是无法指导我们后续的优化工作的,因为我们不知道从哪个网络功能开始着手分析。所以我们需要搞清楚,我们这些流量消耗都干了什么事情。
首先,我们跟业务开发团队进行了沟通,跟开发人员了解流量现状,我们了解到,我们这款 APP 没有采用长连接,所以服务器上的更新,通知等信息是需要 APP 周期性的向服务器发送查询消息来获取的,不同业务的查询消息的发送频率是不一样的。由于业务开发团队是按照特性( feature)来划分的,各自为营,不同开发小组开发的消息结构和发送机制也都是不统一的,而且有很多消息的发送时机选择得也不是很好,服务器返回的内容很多都不是最精简的,存在冗余,所以导致消耗流量过多。
面对如此杂乱无章的流量消耗,我们需要搞清楚我们的 APP 每条 IP 报文的功能,都干了什么事情,理清楚了这些之后才能进行逻辑上的优化,进而进行流量的优化。下面会详细介绍我们是如何理清楚当前的流量消耗的,如何变无序为有序的。
1)按照域名进行流量细分
首先,我们对抓包进行了详细的分析,由于我们的 APP 与后台通信只使用了 HTTP 协议,所以从抓包中是能分析出一些细节的,我们发现 HTTP 报文发往的 host,即域名,例如 www.tencent.com,是不尽相同的,域名是用来区分不同的后台服务器的,代表不同的功能,这种方式有助于不同的后台服务器处理不同功能的报文,这样后台服务器可以按照功能来独立部署和升级。基于这个发现,我们首先对报文按照域名来分类。
下面我们详细介绍一下如何按照域名来分别统计流量。首先使用 wireshark 自带的过滤功能只显示 HTTP 报文,在 filter 处输入 http 即可,如图所示。
图 过滤 HTTP 报文
这样 wireshark 的视图总就只剩下 HTTP 报文了,我们点开一条报文,点开 HTTP 的内容,可以看到有 Host 字段,该字段表示该条 HTTP 报文通信的后台服务器的域名。那么如何统计抓包中共向多少后台服务器发送过请求呢,可以按照如下方法进行。
首先,在上面按照 HTTP 过滤条件过滤之后的基础上,点击 File->Export Packet Dissections -> as “ Plain Text” file,如图所示。
图 报文导出为文本
该步骤可以将过滤后的报文的详细信息(包含 HTTP 头的信息)存储成文本。格式如图所示。
图 报文文本格式
使用 Notepad++ 的搜索功能,搜索关键字“ Host:”,点击“在当前文件中查找”,在搜索结果框中会列出所有的结果,所有的 Host 一目了然。如图所示。
图 报文文本中过滤域名
那么,对于某一个域名,可以使用条件 HTTP.host == "www.test.com" 将该域名的报文过滤出来,如下图所示,然后就可以得知该域名的 IP 地址。一般同一个域名可能有多个 IP 地址与之对应,因为目前后台服务器一般是一个集群,每个终端都会被负荷分担至某几个 IP 的服务器。如图 5-10 所示。
图 确定域名的 IP
然后使用 IP 地址过滤,以上图举例,过滤条件为: IP.src == 140.207.54.68 || IP.dst == 140.207.54.68 || IP.src == 140.207.69.61 || IP.dst == 140.207.69.61。过滤的结果如图所示。
图 按照 IP 过滤的结果
点击 Statistics->Summary,就会统计过滤出的报文的总大小,即该域名下的流量。如图所示。
图 按照域名过滤出的结果
当然,上面是手动分析方法,比较费时,而且无法在自动化测试脚本中实现,这里介绍一种 Python 实现的自动分析脚本的方法。 pcap2har 为一个分析 pcap 抓包的 Python 库文件,下载地址为 https://github.com/andrewf/pcap2har。下面为一个简单的 Python 示例程序,打印了 test.pcap 抓包中所有 HTTP 报文的 host,请求报文大小,响应报文大小。
#! /usr/bin/env python
# -*- encoding: utf-8 -*-
from pcap2har import pcap
from pcap2har import httpsession
dispatcher = pcap.EasyParsePcap('test.pcap')
session = httpsession.HttpSession(dispatcher)
for entry in session.entries:
request = entry.request
response = entry.response
print request.host
print len(request.msg.body)
print response.body_length
可以使用 Python 实现统计每个域名的 HTTP 流量。然后结合上面流量测试方法提到的 GT 的命令行方式进行抓包,我们将手机抓包,从手机上拷贝抓包文件,按照域名统计流量这三部分功能在自动化测试脚本中实现了,再结合手机时间加速方案,我们能很快的进行一轮测试,并得到本轮测试按照域名细分的结果。
经过了多轮测试取平均值的方式,我们得到了如下的结果如下表所示。
表 各域名对应的流量一览
我们测试的 APP 的后台服务器域名共有四个,其中大部分流量都集中在 www.test1.com 上,我们查看这部分报文的内容,发现是无法解析的,因为测试的 APP 与该服务器通信时采用了私有的协议进行报文传输,所以后面我们开始研究如何将这 540KB 流量按照功能来细分。
2)域名下的流量按功能细分
对于报文采用私有协议实现的,要解析这部分报文,需要使用私有协议进行解析,我们 APP 的私有协议的实现方式是类似 Protobuf 的二进制编码方式,即每个协议的结构都是预先定义好的,每个协议都需要按照预定义的格式来解析,即如果协议报文的结构发生变化,解析的方式也是需要更新的。
一开始我们想到的方法是将报文解析算法集成到我们的自动化分析脚本中,这样就能将抓包的报文内容解析出来,但是这种方法带来的后果是自动化脚本中的报文解析算法需要实时同步主线版本中的内容,因为网络交互的报文后续的版本是会不断变化的,这样对于自动化脚本的维护成本就会太高。
后来我们想到了直接在 APP 中输出报文解析的结果,以日志的方式存储,后期自动化脚本获取日志来得到报文解析的结果。当然 APP 的报文日志打印功能需要增加配置,缺省是关闭的,正式版本不进行该内容打印,测试时将该配置打开,记录日志供自动化脚本使用。通过打印日志的分析,最终统计到的结果如下表所示。
表 各业务逻辑对应的流量一览
这里我们选取了 5 个最主要的流量消耗,其他还有很多流量消耗较少的报文,由于优化空间较小,不在此一一列举。至此,我们就得到了我们的产品 24 小时的消耗的背景流量总大小,以及按照域名和功能细分后的各个协议逻辑报文的大小,有了这些精细化的数据,我们才能更深一步的进行优化方案的分析。
二、优化精简
搞清楚了所有交互的报文后,我们需要来优化具体的逻辑和报文,对于各个功能,如何在对原有逻辑无损和不影响用户体验的情况下进行流量优化呢,下面我们详细介绍一下我们的分析方法和优化思路,以及在优化过程中总结出来的法则。
1、单个协议内容消除重复和浪费
项目之初,面对众多的协议,对这些协议的功能和发送逻辑也不是很了解,很多人感觉无从下手。我们的经验就是按流量消耗从大到小依次分析各个协议报文,这里对单个协议的分析包含功能和代码逻辑的分析,优化主要是不影响功能的情况下去除交互报文的冗余。
我们将协议交互的请求和响应各个字段都打印出来,详细的进行分析,很快我们就看到响应报文中是存在冗余和浪费的,最典型的一个协议报文就是动态获取配置,一般 APP 的配置都不是客户端写死的,而是服务器上动态配置的,这样对于一些功能,能方便的在服务器上更改配置,而不需要发布版本。我们的 APP 的配置项也很多,比如报文发送的时间点策略,其他的策略,我们从打印中就能看出,一次响应中的配置项的报文长度就高达 4KB,而且获取配置的报文是一小时发送一次的,一天 24 次,就是 96KB 的流量消耗,在配置不变的情况下,每次响应的 4KB 报文的配置数据是完全一致的,这个完全没必要,每次只需要将有变化的配置项下发下来即可。
我们当即与开发团队讨论,开发团队也表示,当初这种实现方法是最简单的,要做到增量下发配置项实现上复杂一些,因为不同的终端当前的配置项都是不一样的,后台服务器如何判断哪些配置项需要下发给某个终端,哪些不需要,是一个难题。我们经过讨论和方案设计,找到了一个较好的解决方案。下面我们将我们的解决方案总结一下。
我们为服务器的全体配置项引入一个新的参数:版本号 version,从 1 开始递增( 0 表示没有获取过配置项),每次后台服务器修改了某一个配置项,即更新当前最新的版本号,同时记录下该版本号变化的配置项的索引号,每次客户端的请求报文中都必须携带客户端的配置项的版本号,服务器将客户端的版本号与最新的版本号比较,然后从配置项变化表中查询变化的配置项,将变化的配置项的内容和最新的版本号下发给客户端。整个过程如图所示。
图 全量与增量拉取数据对比
例子中 Server 有四个配置项,中间修改了第二个配置项,全量拉取的方法每次都将四个配置项的信息都下发,修改成增量拉取后, Server 只需要维持一张各个 Version 变动的配置项的索引号表,即可实现对每个客户端每次只下发有变化的配置项了。 Version 1 由于是第一个版本号,所以表中记录了所有的配置项索引号,表示客户端第一次拉取的配置项是全量下发的。
我们使用该方法分析了其他的协议,还有两个协议存在该问题,也使用同样的方法进行了优化,效果显著。
使用了该方法优化后,我们仍发现有个别协议较耗流量,其中有一个协议为拉取热词,即 APP 搜索框中推荐的用户搜索最多的词语,这个功能也是所有 APP 中常用的一个功能,如图 5-14 所示。
图 热词示意
即使使用了增量拉取,一天中也会出现 2~3 次的拉取,因为这个内容一天中确实会变化,因为用户每天搜索的词语都是不一样的。由于热词一次下发的量过大,我们最终从功能逻辑上分析, APP 在后台运行,用户没有操作的情况下,有没有必要拉取这个信息?原先的设计是在用户没有操作的情况下,预取该信息,在用户打开 APP 时搜索框直接就显示最新的热词,在用户体验方面当然是最好的了,如果不预取,我们只要保证每次用户点开 APP 去增量获取一次最新的热词即可,所以在移动网络后台运行时我们修改成不发送该协议, WiFi 下的预取策略我们维持了原样,毕竟 WiFi 下是不消耗移动网络流量的。
我们把这一阶段的优化经验提炼成两个优化法则:
法则一:增量拉取数据
APP 与后台服务器交互时,每次只传输有变化的数据,不变的数据不要重复传输。
法则二:界面展示的数据非 WiFi 下不预取
非 WiFi 情况下,对于 APP 界面展示的数据,在 APP 后台运行时尽量不去拉取。
2、报文发送频率和时机的优化
在将单个协议报文的流量优化之后,我们需要继续从系统层面深度挖掘优化方法,我们通过和竞品对比,发现我们每天发送的报文数量是远远高于竞品的,于是我们思考, APP 后台运行时用户没有操作,是什么驱动我们的 APP 发送了这么多报文的 ?
首先我们发现的是信息上报,对于每款 APP 来说,由于运营的需要,需要后台服务器上采集终端的一些信息,比如上面所说的后台服务器的配置更改,每次配置更改后我们需要统计,有多少用户的 APP 配置已经生效,这里就需要在终端拉取了最新的配置后上报给服务器一条信息,就是终端成功更新配置的时间或者版本号。类似于这种运营需要信息上报的地方很多,我们发现 APP 后台运行时这些信息上报都是实时上报的,如上配置项举例, APP 每次成功拉取到最新配置后即实时上报一条信息。这样导致我们的 APP 一天有 30 多条的信息上报,每次信息上报的报文的实际内容其实是不大的,但是报文的头部是很大的,因为需要标识是哪个终端,就需要使用终端 ID,常用的是 GUID,一个 100 多字节的字符串,还有很多其他字段,由于历史原因,我们 APP 的协议报文头共有 400 字节,我们想优化这个报文头,但是经过详细的与开发了解背景后决定先不改了,因为很多字段都是因为历史原因添加上去的,是有用的。
经过思考,我们对这种实时信息上报提出疑问,后台服务器需要立即得到这种信息吗?答案肯定是否的,运营也不是实时去查看这种数据的,所以我们只要保证用户当天上报该类统计信息即可。于是我们做了一个信息缓存,将需要上报的信息先缓存起来,然后周期性的上报,这里我们选取了 3 小时的周期,一天上报 8 次,这种非实时信息上报为我们节省了很多流量。
其次,我们发现对于某些发送频率较高的协议报文,研究了功能后发现移动网络下用户点击的概率其实是不高的,比如视频的推送,应用更新的推送等等,这些功能都是较费流量的,对于这些功能,移动网络下其实发送频率可以降低,但是不能不发,因为存在某些用户,流量是足够的。所以修改后的方法是 WiFi 下发送频率不变,非 WiFi 下发送频率减半,这样流量可以节省一半。
我们把这一阶段的优化经验提炼成两个优化法则:
法则三:实时的信息上报后台运行时改成非实时上报
后台运行时产生的日志,先缓存起来,后续周期性的统一上报。
法则四:非 WiFi 场景降低耗流量的功能的网络通信频率
对于某些网络通信,给用户推送了一些较费流量的功能,这些网络通信在非 WiFi 场景下可以适当降低频率。
3、多个报文合并发送
经过前面的优化,我们已经发现报文的头是有 400 字节的,由于产品开发团队的现状,分属于不同 feature team 的功能都是在各自的模块中实现的,所以各个团队的周期性的任务都是分别进行的,比如后台运行时 1 小时与后台交互一次,这种消息我们就发现有两个, 3 小时与后台交互一次的消息又有两个。这种现状最直接的影响就是报文数量比竞品多很多,报文的协议头开销就不容忽视。简单计算一下, 1 小时周期的报文一天发送 24 次, 3 小时的报文一天发送 8 次,这样一天共有 24*2+8*2 = 64 个消息,报文头开销 400*64 = 25600 字节。
对于这种情况,我们将这些周期性的发送消息进行了合并,放在一个消息中与后台服务器交互,打破了 feature team 的壁垒,这样一天只有 24 次的消息通信,报文头的开销为 400*24 = 9600 字节,流量消耗大大降低。
这一阶段提炼了一个准则:
法则五:合并网络请求,减少请求次数
4、充分利用 WiFi 传输信息
相信进行到这一步,可挖的优化点已经不多,其实换一个角度,我们还能想到一些优化点。目前大部分用户每天都是能连接 WiFi 一段时间的,不管是公共 WiFi 和公司或者家里的 WiFi,我们后台运行的那些报文如果能充分利用好 WiFi,也能为用户节省流量。比如非实时信息上报,前面优化完之后是 3 小时周期上报,但是上报的时机如果用户不是连接的 WiFi,也会上报,就会消耗流量,其实我们做一个简单的处理,就能收到很好的效果,每次非实时信息上报时都判断一下网络,如果是 WiFi,则立即上报,如果不是 WiFi,则再等待一个周期,如果下一个周期 3 小时内用户连接了 WiFi,则在连接 WiFi 的时刻立即上报,如果用户 3 小时内没有连接 WiFi,仍然是在移动网络下上报。
当然,具体的协议和功能需要根据其特点灵活的利用 WiFi 传输信息,在 WiFi 时需要尽量传输信息,不在 WiFi 时要尽量等待下一个 WiFi 连接的到来。
这一阶段提炼了一个准则:
法则六:尽量利用 WiFi 传输信息
当然,流量优化的方法不限于这六个法则,需要结合具体的逻辑,制定最佳的方案。比如长连接对于 push 类的消息的下发是比较省流量的,它只需要少量的心跳来维持连接,然后服务器有更新和推送等消息时直接通过长连接下发下来,不需要客户端周期性的向服务器发送请求,竞品里面有很多逻辑就是使用了长连接,所以流量消耗较少。但是考虑到引入长连接对产品的架构改动较大,所以这个优化只是排了一个长期计划来一步步实现,不可能短期内实现。
2.3 优化过程中的经验与思考
本案例讲解了一般的流量测试和优化方法,简单将我们整个流量优化过程中的一些项目经验总结一下。
1) 流量优化开始,需要对当前流量的协议和各个协议的流量消耗进行精细化监控,摸清当前的现状。各个协议背后的业务逻辑也需要了解清楚,当初为啥要这样设计,报文交互的频率是基于什么考虑的,后续的优化是需要在此基础上继续探讨可行性方案的。
2) 流量优化团队的工作因为涉及到各个开发小组,在项目开始之初是需要得到各个开发小组的支撑许诺的,各个开发小组需要给流量优化项目预留人力的,后续分析的各个优化点涉及的团队是需要进行相关的开发工作的。
3) 小步快跑,优化点按计划分批合入发布版本。流量优化涉及到的优化点比较多,实务比较杂,可以按照一个月一个发布版本的节奏,及时将完成的优化点合入版本发布,不要等到最后一次性合入,因为主版本的代码随着特性开发总是在变的,不及时合入发布版本,时间一长,优化点的代码就会和主线产生差异,合入的代价就会增大。
4) 自动化流量监控平台需要项目之初就搭建,该平台的精细化监控,既可以提供流量优化分析的素材,又可以快速验证每个优化点修改后的版本,会大大提升开发和测试效率。
5) 及时总结,每一阶段的优化完成后,需要将经验总结和固化,后续的优化根据这些经验,能更快的进行分析。
6) 不能为了流量优化而牺牲功能,这一点尤其重要,我们在整个流量过程中都遵循该原则,每个优化点的修改都不能降低用户体验。如果因为降流量,用户的体验降低,这个就是舍本逐末,毕竟,用户体验是第一位的。
本文节选自机械工业出版社《移动APP性能评测与优化》第 5 章。由机械工业出版社华章IT授权。基于移动阅读的考虑,部分内容进行了排版调整,想了解本书全部详细内容,可以在各大书店购买。
参考阅读:手机QQ上传速度提升8倍秘诀:解决速度与成功率的“鱼翅”项目
本次活动我们采取文章留言送书的活动。在本周末前,留言点赞数最高的前 3 名我们将免费赠送本书!(上次还没提交地址的同学请速度)图书由机械工业出版社华章IT提供。
本文由机械工业出版社华章IT授权高可用架构发表。转载请注明来自高可用架构「ArchNotes」微信公众号及包含以下二维码。
高可用架构
改变互联网的构建方式
长按二维码 关注「高可用架构」公众号
由高可用架构发起及举办,为期 2 天的 GIAC 大会已经圆满结束,全部 PPT 可以通过以下文章下载: