请选择 进入手机版 | 继续访问电脑版

默认
打赏 发表评论 12
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率
微信扫一扫关注!

第一部分:内容概述


1.1 本文点评


本文内容是由腾讯TMQ专项测试团队针对手机QQ图片上传速度和成功率问题,在各种复杂移动网络环境下的优化实践总结和整理而成。文章虽是针对手机QQ图片上传这一特定业务功能,但内容中大量涉及复杂移动网络环境下无线网络的特性、特点以及相关第一手测试数据,都是非常珍贵的,尤其值得移动端IM开发、消息推送这种深度依赖移动网络的应用开发者借鉴和参考

强烈建议您同时阅读:《现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障》《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》、《移动端IM开发者必读(二):史上最全移动弱网络优化方法总结》。

1.2 系列文章


本文是系列文章中的第1篇,总目录如下:


1.3 前言概述


最近几年,我们针对 Apps 的网络性能优化工作并不多,但每一次都是投入人手较多、时间跨度较长的大任务。本文将给读者们分享两个较为成功的优化案例:一个是 12 年时帮助手机 QQ 做的图片上传能力的优化工作,主要提升了文件在移动互联网下的上传速度和成功率;另一个则是一年多以前为公司的某产品成功优化网络流量的案例(见下篇《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗》)。速度、成功率与流量正好是 Apps 网络优化的几大重点,希望本文案例中我们分享的思路能够给诸位正在开展或将来会开展此类工作的读者们一些启发。

在本案例中,我们重点讲解了提升上传速度和成功率的“鱼翅”项目,重点分析了在移动网络下影响上传速度和成功率的因素,一次次的调优算法并验证,最终提炼出了能应对网络质量瞬息万变的鱼翅算法。

2012 年初,当时的 Android 版手机QQ 在带宽大而稳定的优质网络下的图片上传速度偏低,在带宽小而质量差的弱网络下传输成功率很低。我们团队尝试着对手机QQ 的图片传输方案进行优化。通过半年多的研究、评测、实验和开发,我们推出了代号为“鱼翅”的适合移动网络的文件自适应传输方案。该方案将手机QQ 的优质网络下的传输速度提升近 60%,弱网络下的传输成功率提升更是高达 8 倍。

时过境迁, 3 年多过去了,国内的移动网络从当年的 2G 为主已然升级到以 3G 甚至 4G 为主要网络覆盖类型,可以说网络质量得到了大幅提升,特别是带宽的提升尤为明显。尽管如此,我们依然相信,“鱼翅”在应对多变的移动网络时的一些核心思想、以及我们在研发鱼翅过程中的一些方法和思考,对今天的 Apps 网络优化工作仍有借鉴意义。下文我们将会分享这些内容。

第二部分:问题背景及解决方案雏形


2.1 背景故事


在讲述鱼翅的核心思想之前先花点篇幅来介绍一下研发鱼翅的背景。 2012 年初,腾讯移动互联网事业群(下文称“ MIG”)的许多产品都有图片分享这一功能(其实,直到现在,用户间的图片分享仍然是移动互联网产品最常见的功能之一),但是用户们却常常反馈,上传图片时经常失败,我们团队就启动了代号为“大白鲨”的专题专项研究测试任务,该任务将针对图片上传这一功能进行深入而细致的横向对比评测与研究分析,旨在提出一套全新的图片上传方案,提升各个相关产品在图片上传这一能力上的用户体验。

任务持续了大半年的时间,名为【鱼翅】的全新方案脱颖而出,它不但吸取了 MIG 几大重要产品(微博、手机QQ 等)在图片上传能力上的精华,同时在我们综合分析大量实验数据后为其引入了数项新的创新策略以及反复调优得到的核心参数。最终,“鱼翅”率先落地于 Android 版手机QQ,极大的提升了这一拥有数亿用户的超级 APP 的图片上传能力,得到了用户们的广泛好评。

值得一提的是,由于我们的任务是旨在用最小的代价优化几大拥有数亿用户的现有产品,所以从一开始我们就将任务的主要发力点定格在终端传输策略的优化上,而尽量不改变前后台通信协议,也尽量不改变后台传输、存储策略。

所以,“鱼翅”是一个单方面优化终端策略的网络优化经典案例。本来我们计划是,如果“鱼翅”效果不错,那么我们就会进一步对通信协议、后台策略进行改进,但是后来由于公司架构发生了很大调整,相关产品从 MIG 移交到了别的 BG,所以该计划只得暂停。

2.2 方案雏形


“大白鲨”的第一个阶段,我们详细分析了当时 MIG 几大产品的上传方案,了解到每个方案中都有一些可取之处、也存在一些都没解决好的问题,于是我们决定把这些各自的“闪光点”都放到“鱼翅”中作为一个基础。同时,我们针对大家都没处理好的一些问题提出我们的一些改进设想,于是,我们有了鱼翅的方案雏形。

由于不便展示具体流程图,故仅将其要点和相关考虑罗列如下:

  • (1)必须分小片传输一个文件(图片):
    理由:由于当时后台的能力,无法支持单个网络包传输失败后对包里剩余字节的断点续传,所以若整个文件(图片)放在一个网络包里进行传输,一旦失败,就必须重传整个文件,这样给用户带来的流量浪费是巨大的。因而采用把一个文件分片的方式传输,则只需要在某一个分片失败后重传这一个分片。同时,单个消息越大传输时越容易失败(快速数学证明:若文件大小接近 0,则传输成功概率接近 100% ;而文件大小无穷大,则传输过程必然会失败),而移动互联网的整体质量比有线网络要差,相同大小的消息会更容易失败;因此就应该把一个较大的文件分成一个一个的小片进行传输,每个小片更容易成功一些。
  • (2)不同类型的移动互联网下的分片初始大小应该有所不同:
    理由:不同移动互联网的带宽和稳定性的差异都很大,如 WiFi 和 2G,使用不同大小的初始分片应该能更好的适应对应类型的网络,但是至于每种网络下的初始分片到底多大,这需要进行实验。
  • (3)在上传一个文件(图片)的过程中,应当尽可能动态增大分片大小(例如,后一片是前一片的 N 倍),以减少分片数量:
    理由:分片动作会带来不少额外开销,如 C / S 两端拆分与合并分片的时间、传输时的额外流量( HTTP 头等)、每个分片的 RTT 等等诸多开销,所以理论上传输同一个文件用的分片数量越少,应该额外开销越小。
  • (4)确定每个分片是否要继续增大之前,要检查网络类型是否发生了变化,一旦跟前一片传输的网络变得不同,则新的一片不能继续增大而是转而用新网络类型下的初始分片大小进行传输:
    理由:移动互联网下,由于用户的“移动”而时长发生网络类型切换的事情(如, 3G 变 2.5G),一旦网络类型变了,其带宽、时延、稳定性等等因素都发生了很大的变化,所以需要分片大小需要“归零”,以迅速适应新的网络,减少失败的概率。
  • (5)分片一旦传输失败,应当使用该网络下的初始分片大小进行重试:
    理由:若网络类型并没有产生切换,但某分片传输失败了,则说明该网络的质量可能已经下降到不再适合传输这个大小的分片,会有较高再次失败的可能性,因此转而重新用该网络下的初始大小的分片进行重试,以提升重传成功概率、同时减少再次失败所带来的流量浪费。
  • (6)每个分片都有一定次数的失败重传机会,当一个分片的所有重传都失败了,才定义为图片传输失败。
  • (7)配合后台服务器能力,待用户手工再次重试失败传输的图片时,能断点续传。

2.3 待解开的疑问


鱼翅的这个方案雏形尝试改进了当时各业务上传图片时存在的不少弱点,举几个例子。例如:

  • 有的业务不把图片进行分片传输会导致的失败率高、流量浪费多;
  • 又例如有的业务尽管用分片传输策略,但分片的大小时是固定的,这样一来,优质网络下的带宽利用率可能就很低(传输速度远不如不分片传输的那种方案);
  • 还有的方案是重传失败分片时并不改变其大小,因而重传的成功率并不高。

尽管新方案有了不少改进点,但我们心中仍然存在不少疑问,若能找到答案,则鱼翅就会更加可靠和强大,这些疑问如下:

  • 疑问 1:关于“长连接”:
    由于图片传输时,使用的是 HTTP,那么是否当时的所有运营商网络都支持 HTTP 的 Keep-alive 这样的长连接?如果不支持,那么会导致每一个包含分片的 HTTP 请求都要进行一次 TCP 的 connection,依据我们的经验,移动互联网下的连接成本很高, 2G 网络下甚至有时高达 2S。如此大的分片开销是完全没法接受的!所以,如果运营商网络都支持 Keep-alive,则一个文件(图片)的多个分片传输仅需首个分片传输前建立一次 connection ;甚至,多个连续发送的图片都可以复用第一张图片建立好的连接。
  • 疑问 2:关于分片大小:
    如果在传输过程中,后一片分片总是 N 倍于前一片分片的大小,那么,不同类型、不同质量的网络下是否存在最适合的初始分片大小和最大分片大小?如果没有最大分片,岂不是越到后来传输失败的概率越大?
  • 疑问 3:关于分片对于速度的影响:
    显而易见,如果将原本不分片的传输方案改造成分片传输,由于分片引入的开销,必然导致传输速度会有下降;那么,有没有办法让这一下降的幅度尽可能的小,从而在不影响用户速度体验的前提下,通过分片方式得到提升传输成功率和减少流量浪费的好处呢?
  • 疑问 4:关于分片传输成功率:
    对于单个分片的传输,其失败的诸多原因中最主要的到底是什么?如果能找到办法解决这个最主要的导致单片失败的问题,岂不能提升单片传输成功率,从而进一步提升整个文件(图片)的上传成功率呢?
  • 疑问 5:关于失败重传策略:
    当前的失败重传策略是否奏效,是否是最好的?如果不是,那么还不如不重传,因为如果重传成功率低,必然带来新的浪费。

为了解开这五大疑问,我们开始了长达数月的几类自我解惑的工作:

  • 对于“疑问 1”这样的有关运营商的问题,我们找到了熟悉相关行业技术的专家请教,得到初步答案后,开始通过各种网络下的实验进行核实。
  • 对于后面四个疑问,我们先采取在不同特征网络下的大量实验、配合抓包数据分析的手段来定性。
  • 同样对于后面四个疑问,在基本定性之后,我们则采取开发实现鱼翅、然后在不同网络下进行参数的调优实验的方式来定量。
  • 在定性和定量阶段,不断根据更加深入的认知,去优化鱼翅的方案。

功夫不负有心人,在成百上千次实验后,上述 5 个疑问的初步答案基本浮出水面:

  • 关于“长连接”的答案:
    当时的运营商网络基本都支持 HTTP 的 Keep-alive,通过实验发现,不仅一张图片的分片可以复用第一分片建立的 TCP 连接,有的时候时间间隔稍短的下一张图片甚至也可以复用上一张图片的连接。这样就不必担心分片会带来的巨大网络开销。
  • 关于分片大小的答案:
    不同网络下的初试分片大小非常难确定,或者根本就不存在,但最好根据网络的理论带宽各自取一个较小的经验值(后文会给出);分片的大小上限则应该存在,后文讲述的鱼翅核心思想会提到为什么有,且我们怎么去找。
  • 关于分片对于速度的影响的答案:
    基于上一个问题的答案,这个问题比较好回答,就是只要有算法能尽可能快的找到“当前网络下的分片上限”,用这个上限值去发送分片,就能将分片带来的速度下降体验减轻到最低。
  • 关于分片传输成功率的答案:
    根据我们大量实验的结果,发现移动网络的质量经常会发生的特殊变化(下文会详细讲述这个“特殊”)是传统的网络超时算法不能适应的,而这种不适应,非常容易导致传输超时带来的失败。所以,我们把寻找适合移动互联网的“传输超时算法”作为提升分片传输成功率的关键。
  • 关于失败重传策略的答案:
    还是由于移动互联网质量有时发生的特殊变化,所以当时失败重传策略的确有优化空间,下文会讲述如何优化这个点。

第三部分:“鱼翅”项目的要点


随着对几大疑问的不断认知,我们也不断地改进着鱼翅,终于得到了 1.0 版本的鱼翅方案,本章节将会与各位详细聊聊鱼翅正式版的一些核心思想。

3.1 鱼翅 1.0 主流程


相比鱼翅的方案雏形, 1.0 版本的主流程有如下改进:

  • 1)为了能更为快速的寻找适合当前网络的分片大小上限,分片大小的计算逻辑抽象成独立的复杂模块,我们叫它 SSCM,它专门负责根据一个文件的已传输分片的统计数据来计算下一个待发送分片的大小,这样就实现了“自适应动态根据网络现状调整分片大小”的效果; SSCM 是鱼翅的要点之一,关于 SSCM 的详细情况下一小节会细讲。
  • 2)单一分片在“雏形”中会直接交给 HTTP 协议栈进行传输,而在 1.0 版本中,这个“传输”动作改进成较为复杂的一个独立事务,全新的超时处理方法的秘密就在这里,单片发送成功率的提升就是这样达到目的的,所以“单片发送流程”也是鱼翅的另外一个要点,详情也会在后续小节详述。
  • 3)重试策略也是鱼翅的一个要点,相比方案雏形最大的改进,就在于每一次重试的时间间隔不再是“立刻重试”,而是选择类 TCP 超时重传机制的指数回退方式进行,因为我们做了多次实验发现,移动互联网下做立刻重试是非常不明智的,重试失败率近 100% ;因为,移动互联网网络出现问题后的恢复周期远长于有线网,需要给它更长的时间让其主动恢复,或者手机用户主动运动以改变所处的网络的质量,而运动也需要花较长的时间;因此我们选择不立刻重试,而是等待一段时间(例如, 10S),如果再失败,我们等待更长时间。经多次测试发现,如此的策略能极大提升重试成功率,避免不必要的重试。

接下来,我们展开讲述一下 SSCM 和单片发送流程的主要思路。

3.2 “鱼翅” 1.0 的分片大小计算模块 SSCM 的要点


SSCM 的核心思想是“鉴古通今”,即每一个分片发送的大小、速度等信息都是后续分片大小计算的依据。因为移动互联网随时在发生着变化,我们处理当前的事务时,一定不能忘记刚刚发生的事情以及历史上发生过的事情,这些数据都是宝贵的财富,我们应当想办法充分使用它们。同时,由于移动互联网带宽资源是有限的,所以尽量不要做为了搞清网络状况而发起一些额外探测包的事,这样只会加重本已负担很重的网络负荷。因此,应要想办法利用必要的数据包发送时所反馈出的一些信息来分析网络状况。

通过对大量的实验数据进行分析和思考,我们认为每一个网络(某个时间、某个地点的某一个类型的移动互联网)都应该有一个最适合的分片传输大小,在这个大小下进行传输,所能达到的速度相对接近某个极大值,对该网络的带宽利用也最为充分。基于上述考虑,我们将 SSCM 的原理画了一张手绘图,下面结合图 5-1 研发过程中的手稿,谈一谈 SSCM 的要点。

1.jpg
▲ 图1 SSCM 原理手绘图

1)把一个文件传输的全过程按照分片大小的增长快慢分成三种状态:
QUICKSTART(快启动,分片以一定倍率快速增长)、 SLOWSTART(慢启动,分片以一个远小于快启动增长倍率的小系数缓慢增长)、 STABLE(稳定态,分片大小不在变化)。

解释:状态迁移的触发条件是“分片传输速度随分片大小的增大而变化的幅度”,即图上的“归一化斜率”。结合“手绘图 1”,通过大量实验发现,任意网络的最大可用带宽肯定不同,分片从小变到大,其传输速度也随之增大(增速也不同),但是分片增长到某个大小(我们姑且称这个大小为 Ss,其实这是一个范围)之后再继续增大,对速度不仅不再有正向影响、有的网络下反而会让速度减小。这个实验结果很重要,因此鱼翅在传输图片时最初的状态是 QUICKSTART,目的是以一个较快的增速把分片大小增大到 Ss,而不希望待文件(图片)都传完完毕时,分片的大小仍比 Ss 小很多,这样的上传是没有充分利用网络带宽的。而快启动之后会切入慢启动,即从快启动下的最大分片 Smax 回退到前一个次大小分片 Slmax,然后从 Slmax 为基数、以一个相对较慢的微调增速放大分片,最终找到 Ss,进入稳定态不再改变分片大小,直到发送完毕。

可能有人会问,跨过 Ss,继续增大分片有何不妥?两点理由: 1 是有的网络下速度反而下降,原因是网络负担加重会导致 TCP 重传增多(实验结果); 2 是分片越大,失败概率越高(数学和实验双重证明)。

STABLE 态下如果速度发生巨大变化(我们的经验值是,超过 20% 的变化),我们认为网络质量发生了巨大变化,当前的 Ss 已经不适合了,就会且回到 QUICKSTART 重新寻找新的 Ss ;这里之所以不会试图分析变化趋势而对原有 Ss 进行微调,主要是无法做简单分析来判断到底网络是变好了还是变坏了,读者朋友们有兴趣可以想想。

2)不同类型网络下的初始分片大小皆为测试经验值,具体数值是多少借鉴意义不大。原则就是带宽越小的网络初始分片大小越小,带宽相同的情况下, WiFi 下的初始值也大于移动网络的。

解释:尽管 3G 网络的速度很多时候都跟 WiFi 差不多甚至还更快,但是 3G 网络的流量收费,而 WiFi 不收,所以保守一点进行首片试探。

3)若待传输图片(文件)小于某个经验中的“较小值”,我们认为是“小”图(文件),传输它时对应网络下的初始分片大小会增倍。

解释:对于小图,总共的分片数量较少,所以通过放大初始分片大小,可以显著减少分片数量,从而提升速度效果明显。

4)每一种状态下的分片大小增长因子都不同, QUICKSTART 下是相对最大的值 N,慢启动下是比 1 略大的 M,稳定态下就是 1(不改变大小)。

5)每一个新计算出的分片大小都会使用不止 1 次,计算是否切换状态的速度也用的是多次的平滑值,原因是大量测试发现,移动互联网的网络速度抖动比较大,因此希望多次确认出一个稳定的速度,不然很有可能因为某一次速度的突然降低而找到一个远小于真正 Ss 值的稳定态。(在鱼翅的 1.1 版本中这个点有较大的改进,后文会提及)

6)判断几个状态是否切换用的是分片大小、平滑速度一起计算出的“归一化斜率”,这个斜率能较为准确的反映上面“手绘图”中的分片大小于对应速度的曲线图。具体用什么斜率来作为切换也都是基于实验经验值,一开始鱼翅用的是图中的角度 5 的 Tan(),各位读者有兴趣也可以自己尝试找找适合自己业务的这个值。

7)对于文件末尾的处理,鱼翅也是由大量实验结果分析得出:即发送一个很小的剩余文件尾(哪怕只有几个字节),其所带来的额外开销,例如 RTT 延迟也跟较大的分片差不多,因此鱼翅方案对于剩余文件大小小于当前计算出的最新分片大小的 X 倍时,就会将剩余文件内容全部放到最后一个分片中发送,避免出现“小尾巴大开销”的浪费。

讲到这里,鱼翅的核心思想已经陈述过半。相信经验丰富的读者们一定设计过比 SSCM 复杂的多状态机,但是这里需要强调的是,这个模块的策略及其核心参数的最终值都是对成百上千次实验结果的分析后逐渐得出的,这个过程很苦、也很美妙。

3.3 鱼翅 1.0 单片发送流程的要点


在鱼翅研发过程中,我们对于如何能提升“单片传输成功率”这个难题可谓绞尽脑汁,试尽了各种办法。首先,需要提到一个重要信息:通过大量实验,我们发现了移动互联网下文件传输失败的一个重要原因,即移动网络的质量/带宽经常会发生“跳变”、而不像有线网络那样的“渐变”,这就导致无论怎么设置网络请求的 RTO(超时重传时间)值都不合适,大部分失败都是因为应用层自身超时造成,而这样的超时失败很可能发生在一个分片已经完成了 99% 的数据传输时,其所带来的用户流量浪费显而易见。

因此,我们决定大胆放弃传统意义上的 RTO 概念,转而提出 MNVT( Max Net Vacuum Time,最大网络真空时间)概念,这样的改进,经实验和实际运营数据双重证明,单片传输成功率提升明显。

稍微展开点讲述单片发送流程里的几个要点:

  • 1)网络真空时间 NVT 就是指,应用层发起的文件传输过程中,通过监控网卡状态,发现的传输层连续没有任何数据发送的时间长度。
  • 2)在一个分片上传过程中,我们放弃了传统意义的请求 RTO 超时机制,转而在发出上传请求后,启动一个独立线程去监测出现的 NVT 是否超过了设定阈值( MNVT),我们的 MNVT 也是个实验经验值,一直根据运营数据在持续调整。

一点解释,如图 5-2 所示。

2.jpg
▲ 图 5-2 网络真空对 RTO 的影响

如图,通过大量真实场景下的测试,抓包分析,我们发现一个图片(文件)的分片在移动互联网下传输过程中,这个网络的质量经常可能发生比较剧烈的变化,这种变化是“跳变”而非“渐变”,可能前一秒钟网络发送速度是 5KB / S,而下一秒中就变成了 0.1KB / S,因此即便是动态的根据前一个分片的实际发送速度来确定当前分片的 RTO,都是不具备参考性的,非常容易因为该值设定不准确而产生失败。同时,由于移动互联网下的流量都是要花钱的,所以用户已经花掉的流量应当尽量为用户所用,如果总在已经传输 90% 多时因超时而重传,这就会极大的浪费用户的流量。

所以综合以上提到的“ RTO 很难设定准确,带来许多失败”以及“为用户尽可能省流量”的因素,鱼翅在一个分片发送过程中就通过探测每个监控间隔是否为 NVT 来确定是否还要继续等待分片发送,如果已经有 MNVT 这么长的时间都没任何数据上行了,才会认为该分片彻底失败,因为这样的情况发生了,只能说明网络已经糟糕到极致了。

3.4 鱼翅 1.0 之后的几点重大改进(鱼翅 1.1)


这里提到的“鱼翅 1.1”其实是在鱼翅 1.0 落地手机QQ Android 版之后,尝试在 iPhone 手机QQ 上落地时,又进行了许多实验,根据实验结果,我们对 1.0 版本进行了数项非常有效的改进,于是得到了 1.1 版本的鱼翅。总体来看, 1.1 相比比 1.0 的效果好在两个方面:1. 成功率保持不变的前提下,传输速度更快了; 2. 弱网络下的用户等待时间变短(注: 1.0 在有的较差网络下,会让用户等待很长时间,才会宣告文件传输失败)。

这里也花一点篇幅简单提一下这些改进点,相信对各位读者的优化工作也会有些启发。

1)MNVT 的单一衡量标准,修改为“ MNVT( 最大连续真空时间 )”和“ MSNVT( 最大累计真空时间 )”,其中 MNVT < MSNVT。

理由:首先是后来经过大量测试,发现有不少网络下都是连续真空出现了 10s 了,又恢复了几个字节的极小数据传输,而后又连续真空 10 来秒,这样一来传输一个文件(图片)要花特别特别长的时间,即便最终成功用户也是很难接受的;所以引入了 MSNVT,即一个分片传输过程中,所有发生过的 NVT 的累加值为累计真空时间 SNVT,其上限为 MSNVT,若 SNVT 达到了 MSNVT,分片传输也宣告失败。

2)分片失败后的重试间隔除了指数回退( Ns\2Ns\4Ns),再增加一个“有效重试”检查。所谓“有效”就是每一次重试时检查一下当前网络是否断开,如果是断开的状态,就不做重试(因为此时的“重试”是无效的,根本不会发送),而是继续等待一个相同时间间隔,最长等待到一个上限时间 Xs,如果还是网络断开的状态,就认为“这一次重试放弃”,直接进入下一档(例如 20s)的回退间隔。

理由:在网络断开时不做无意义的重试尝试,那样做就是浪费资源(流量、电量等)。

3)为了提升 WiFi 下的传输速度,这一版鱼翅在 WiFi 网络下的初始分片大小进行了大胆放大;因为 WiFi 下的流量免费,失败重传代价很低。所以读者朋友们也可以大胆尝试一个比较夸张的值,但最好别“不分片”,毕竟还是有可能会失败的,而失败后至少重传会浪费用户的时间。

4)为了进一步提升 WiFi 下的体验,缩小速度上与“不分片传输”的差距,鱼翅 1.1 的 WiFi 分片大小策略为“只增不减”(除了失败情况下,会从初始分片大小开始重新增长)。即归一化斜率满足增长条件时,就直接增长,不做多次确认;当归一化斜率达到迁移 SLOWSTART 条件时,也不做迁移,而是维持当前分片大小继续发送。

5)WWAN(非 WiFi)网络下分片策略修改为“单增多确认”,确认次数为 2 次。

理由:所谓的“单增多确认”就是不像鱼翅 1.0 那样每个计算出的分片大小要使用 N 次,为了确认对应的速度值;相反, 1.1 版里变成了一个分片大小在默认情况下就使用 1 次,如果归一化斜率满足切换状态条件了,才会把这个分片大小的值再重复用一次以达到“确认速度是否稳定”的目的,最多两次确认后,归一化斜率依然满足状态切换要求,则发生状态切换,调整分片增长率。这是为了“更加迅速的”从 QUICKSTART 达到稳定态,以减少“图片传完了还没达到 Ss”的情况的发生。

6)WWAN 网络分片大小设定一个上限。

理由:大量测试中发现,有不少非 WiFi 场景下,分片的大小会变得非常的大,这样一旦失败,就会浪费巨大的用户流量,所以为了以防万一的失败,就给非 WiFi 下的分片大小设定了一个经验值上限。

7)判断是否为 NVT 的条件变成“一个监控间隔内是否有超过 Y 个字节的上行数据”。

理由:同样是通过大量测试发现,如果严格按照一个监控间隔内完全没有数据传输才算 NVT,那么经常会在一个间隔内出现几十个字节、甚至几个字节的极小流量发出,而本来即将到达 MNVT 就宣告失败的一次传输又将继续等待下去。通过实验抓包分析,我们才知道这样的极小流量,在许多时候,是一些网络控制包或者单一的 TCP 重传包,这都说明网络其实很差,不应该为这一个包而继续等待,浪费用户的时间。

第四部分:探索过程中的经验与思考


前一个章节已经非常详细的剖析了鱼翅两个版本的核心思想,其实除了鱼翅方案本身,我们半年多探索鱼翅的过程、过程中的各种实验评测方法以及用到的工具,也是我们希望分享给各位读者的。

4.1 基础决定成败:运营商是否支持 keep-alive?


但凡决定要做一个比较大的事情,必须先把一些直接影响成败的基础工作做好,否则稀里糊涂投入了许多资源,最后若由于基础有问题,最终导致失败是非常浪费的。

对于鱼翅来讲,有一个“基础问题”必须先有一个可靠的答案,我们才敢投入四五个人大半年的时间,那就是前文提到的第一个疑问——“运营商对 HTTP 的 Keep-alive”的支持如何?因为如果运营商不支持,则整个的鱼翅方案是不可行的,分片会带来传输速度的极具下降,任何局部的优化和研究就失去了意义。

所以,为了后面的“大军投入”,我们先花了几天从两个方面来搞清楚这个问题的答案:

  • 1)是请电信方面的专家咨询;
  • 2)是自己动手对几种典型的运营商网络(移动 2.5G,联通 2G / 3G 等)进行测试,抓包分析。

当然,最终的答案是:这些网络都支持,只是各个运营商支持的程度不一样,但是完全不影响我们鱼翅的性能,所以,我们决定大兵压上。

4.2 工欲善其事必先利其器


这句话绝对是真理!大白鲨专题专项任务的前期是对现有业务的各种方案进行性能测试加方案分析,但是中后期是要出优化方案,这已经不是简单的评测工作,尤其当我们面对鱼翅方案雏形时所联想到的那么一大堆问题的时候。

我们意识到要解决这些疑问以及解决后面越来越多的疑问,我们需要:

  • 1)为了找规律、分析问题、调优方案的核心参数,我们需要在 Lab 里进行大量的调试、实验、测试,也需要在真实的移动互联网下做大量的真机对比测试。
  • 2)到“外面的世界”、即移动互联网的真实场景(运动的地铁、公交,繁华的商场等等)中去验证鱼翅的真实效果,还要根据当时的测试结果实时调整参数值看新的效果;同时,发现和定位更多只有在真实网络下才能发现的新问题。
  • 3)无论是上面的哪一条,我们都需要尽可能的多抓取网络数据包来分析,因为光看 log 是远远不够的。

以上的这些事情是整个评测研究过程中天天都要做的,用现有的开发环境我们勉强能对付第一条,但代价巨大:

  • 因为我们需要,每修改一个参数值就 build 一个版本,安装到手机上,然后测一遍各种网络下的表现;
  • 还需要连着 usb 线用 adb shell 配合抓包;
  • 鱼翅的参数非常多,我们还需要测不同参数值组合的效果,不用算也知道,我们需要编译安装的版本是个超大的数字!如果真按这样的方式开展工作,就算花整整 2 年的时间,也未必能完成鱼翅的实验、调优工作。

对于第二条,我们不可能搬 N 台笔记本连着 N 个手机去地铁里做的,而当时的业界还没有哪个现成的工具可以支持单纯用台手机就能进行 APP 的简单调试工作。因为我们一方面要看实际运行起来的一些白盒数据,根据这些数据还要修改鱼翅的参数,如果突然出现问题我们还希望看相关 log 等更多信息。

所以,我们最终决定自己开发一个“组件(工具)”,这个组件可以跟我们的被测 APP(鱼翅方案的 demo)绑到一起,可以实现“随身调试”,具体来讲:

  • 一边操作被测 APP,一边通过同一手机直接观察的性能指标的变化,例如分片大小、传输实时速度、状态机状态、失败原因。
  • 通过手机实时修改一些关键参数却不用重新编译和安装,而是直接在修改后操作 APP 进行测试。例如更改不同状态下的分片增长率、初始分片大小、 MNVT 值等等。
  • 在实际环境中测试时,遇到偶然失败的情况或者速度变得很慢,能有一些预先打好的日志可以直接通过手机查看分析。
  • 最重要的是,做任意操作时,我们可以直接通过手机抓取网络数据包,便于事后做详细网络分析。

不难想象,这样一个“组件”在我们研发鱼翅的整个过程中起到了非常关键的作用,整个项目组的所有人、所有手机每天都用它。这么好的移动互联网 APP 调优利器,我们不敢私藏, 2013 年上半年我们认认真真的把它做成了一个在腾讯公司内所有同事都可使用的公共组件, 13 年下半年我们又将它发布到了公司外, 16 年初我们在 Github 上将其开源,它的名字叫:GT(腾讯GT开源工程链接)。

4.3 外面的世界更精彩


相对于 office、 Lab 而言的真实移动互联网使用场景就是我们这里所指的“外面的世界”,我们还特别关注那些网络质量不稳定、比较差的真实场景。原因是,从本任务一开始,我们就定了两条优化的方向:

重点优化优质网络下的传输速度,而不特意优化差网络下的速度。因为质量差的网络下,传输很容易失败,首先需要提升的是成功率;其次,差网络的带宽本来就小,无论怎么优化,其最大速度通常较低,用户很难感知提升效果。

重点优化差网络下的成功率,而不特意优化优质网络下的成功率;因为质量优质的网络,无论哪种方案的成功率都接近 100%,即便花了很大功夫优化,也难以让用户感知。

由于办公室网络已经满足“优质网络”的条件,所以我们主要在公司里用 GT 来调优鱼翅的速度。但是公司里很难模拟出“外面”的真实的移动互联网场景,所以对于“提升鱼翅的传输成功率”的相关调试和对比测试我们都需要在 GT 的支持下到“外面的世界”去搞。特别是优化后的对比测试,我们必须找那种容易区分出优化前后效果的场景,否则优化前后的成功率都接近 100% 的情况下就不知道是否优化有效了,而这样的场景往往是质量较差的网络。

那么面对如此纷繁复杂的“外面的世界”,我们必须得选择满足如下要求的场景来:

  • 使用手机上网的人多的场所,这样的网络会比较容易拥塞。
  • 不断运动的场所,这样的网络多切换。
  • 信号存在干扰或者部分屏蔽的场所,这样的场所有效带宽低。
  • 网络整体质量不能太差的场所,如果太差,以至于优化前后的方案的成功率都接近于 0,那么就有没有“区分度”了。

项目初期,我们做了多次“场外测试”,目的是为了寻找有着上述特征的场景。

最终我们选定了几个比较有代表性的场景,就好像赛车时的经典赛道,这里列出来供大家参考:

  • 北京的地铁 2 号线环线、 10 号线环线(环线有个好处,就是不用总是上下车换乘)。
  • 上下班的班车上。
  • 北京南站。
  • 中关村鼎好电子商城。
  • 一辆从公司到地铁站的四环路上的公交车。
  • 一条从地面到地下的地铁站隧道。
  • 家里的卫生间或者厨房。
  • 上万人同时使用手机的演唱会现场。

就是在这些场景下,我们拿着两个装有不同版本的鱼翅和 GT 的手机,在不同的运营商网络下发送着一张接一张的图,对比着 GT 输出的性能指标,思考着背后可能发生的事情,一次次的推翻了我们的一个又一个的中间版本,因为每次在这样的场景下本来在公司里感觉良好的“优化版本”总是会出现一个又一个的新问题。而一旦出现这样的新问题,我们会立刻查看 GT 输出日志做现场分析,有的时候能立刻想到解决办法或定位到根因,但有的问题只能拿着采集下来的现场网络数据包回公司做详细分析。

正是这样的一次次的场测,我们了解到了:

  • 移动互联网的网络带宽很容易出现“跳变”,下一秒中的传送速度可能降到前一秒的几十分之一,有线网的 RTO 机制解决不了因为超时导致的大量失败。
  • 移动网络里经常会有“网络真空 (NV)”,即便信号满格也传不出去 1 个字节。
  • 在变幻莫测、质量很不稳定的移动互联网下, TCP 的表现非常顽强,从不轻言放弃。
  • ……

通过这样一次次的场测,我们发现了一个个未知的移动互联网特征,我们见招拆招,不断修改鱼翅方案和参数值,才有了最终的鱼翅 . 这个过程充满艰辛,但也很有成就感,比如,灰度发布期间,看到运营数据里一天天提升的图片上传成功率。

本文到此就结束,本文下一篇是关于如何优化 APP 网络传输流量的,详情请查阅《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗》。

(原文链接:点此进入

附录1:更多相关文章


1)关于网络通信的基础文章:


2)涉及移动端网络优化的文章:


3)如果您觉得有些网络问题,已无法从应用层找到答案,那么以下这个系列是你的“菜”:
    以下文章为IM/推送技术开发的边界知识,但有助于你从物理层理解各种网络问题。如无兴趣,可忽略之!

附录2:QQ、微信分享的技术文章汇总


[1] 有关QQ、微信的技术文章:
微信后台团队:微信后台异步消息队列的优化升级实践分享
微信团队原创分享:微信客户端SQLite数据库损坏修复实践
腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率
腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)
腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)
微信Mars:微信内部正在使用的网络层封装库,即将开源
如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源
开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]
微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)
微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]
微信团队原创分享:Android版微信从300KB到30MB的技术演进
微信技术总监谈架构:微信之道——大道至简(演讲全文)
微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]
如何解读《微信技术总监谈架构:微信之道——大道至简》
微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]
微信异步化改造实践:8亿月活、单机千万连接背后的后台解决方案
微信朋友圈海量技术之道PPT [附件下载]
微信对网络影响的技术试验及分析(论文全文)
一份微信后台技术架构的总结性笔记
架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]
快速裂变:见证微信强大后台架构从0到1的演进历程(一)
快速裂变:见证微信强大后台架构从0到1的演进历程(二)
微信团队原创分享:Android内存泄漏监控和优化技巧总结
全面总结iOS版微信升级iOS9遇到的各种“坑”
微信团队原创资源混淆工具:让你的APK立减1M
微信团队原创Android资源混淆工具:AndResGuard [有源码]
Android版微信安装包“减肥”实战记录
iOS版微信安装包“减肥”实战记录
移动端IM实践:iOS版微信界面卡顿监测方案
微信“红包照片”背后的技术难题
移动端IM实践:iOS版微信小视频功能技术方案实录
移动端IM实践:Android版微信如何大幅提升交互性能(一)
移动端IM实践:Android版微信如何大幅提升交互性能(二)
移动端IM实践:实现Android版微信的智能心跳机制
移动端IM实践:WhatsApp、Line、微信的心跳策略分析
移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)
移动端IM实践:iOS版微信的多设备字体适配方案探讨
>> 更多同类文章 ……

[2] 有关QQ、微信的技术故事:
技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码
技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史
开发往事:深度讲述2010到2015,微信一路风雨的背后
开发往事:微信千年不变的那张闪屏图片的由来
开发往事:记录微信3.0版背后的故事(距微信1.0发布9个月时)
一个微信实习生自述:我眼中的微信开发团队
>> 更多同类文章 ……

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

上一篇:请教NIO框架mina在棋牌类游戏中的问题下一篇:关于TCP可靠性传输特性为何在系统内核层实现的疑问

本帖已收录至以下技术专辑

推荐方案
评论 12
也只有大厂才有这样的人力来专门研究移动网络下这样的问题,好文已收藏!
签名: 该会员没有填写今日想说内容.
移动网络比pc网络真是复杂多了,资料很棒...
签名: 秋天到了,终于凉快了
之前看到过腾讯开源工程目录下的GT项目 https://github.com/Tencent/GT,没想到是这么用的,果然好东西
签名: 秋天到了,终于凉快了
学习了,感谢分享!其中速度变化的快慢决定到哪个状态不是很明白。
正在找的资料,赞一个
什么时候把数值开源出来
发现自己原来这么菜
签名: 不错!!!!!!!!!!!!!!!
细节体现价值...
很少用到分片了,都是直接表单过去了
签名: 来看看啊
大厂追求极致体验的使命!
我只是来膜拜大神的
签名: 努力......
打磨出来的细节着实让人震惊
签名: 努力!!
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部