无限网络性能 -- 移动网络优化

高速浏览器网络性能 -- 第二部分 无线网络性能 -- 第8章 移动网络优化



首先,通过长连接把延迟减到最小,把你的服务器和数据放在地理上离用户近的地方,优化你的TLS部署,还有我们曾经谈到的所有其它协议优化,这些对移动应用来说尤为重要,延迟和吞吐量总是很珍贵。类似的,所有Web应用性能的最佳实践也同样适用,第10章会谈到。

然而,移动网络对我们的性能策略有一些新的、特定的要求。由于设备环境限制(the form factor of the device)、无线接口独特的性能特征、电池寿命的影响,设计移动网络应用需要仔细规划并思考内容的呈现。
可能是因为展示层最容易控制,所以诸如响应式设计这样的主题,往往受到最多的关注。然而,大多数应用昙花一现,常常是由于对网络性能不正确的设计假设导致的:相同的应用协议,但不同的物理发送层有不同的限制因素,如果未加以考虑,将导致响应慢、高延迟变化,最终给用户带来糟糕的体验。糟糕的网络决策也会严重影响设备的电池寿命,这无疑于雪上加霜。
这三个限制条件没有通用的解决方案。我们有展示层的最佳实践,也有针对网络和电池寿命性能的最佳实践,但它们常常是有矛盾的。要靠你和你的应用找到你需求的均衡。有一点是确定的,无视这些限制因素,你肯定走不了多远。
有鉴于此,我们将不会过多讨论展示层,因为不同的平台,不同类型的应用差别很大 -- 而且,有很多书籍专注于这一主题。无论用的是移动还是联通,Android还是iOS,都会受到同样的限制,the radio和电池,这是我们本章重点讨论的问题。

在这一章中,术语“移动应用”采用它最宽泛的定义:所有我们关于移动网络的性能的讨论同样适用于native applications,与浏览器运行的平台、应用,浏览器厂商无关。

节省电池电量


一谈到移动,省电对各方都是一个很关键的问题:设备制造商,运营商,应用开发者,还有我们的应用程序用户。如果有疑问,或者想知道为什么或某个移动行为怎么样表现合适,就问一个简单的问题:它对电池寿命有什么影响和改进?事实上,这是你在设计应用程序的每一个功能时应该要问问的好问题。
移动网络的网络性能天生与电池性能有关。事实上,无线电接口的物理层特别针对电池寿命做了优化,以应对如下限制:
  • 全功率使用广播会在几小时耗干一个充满的电池
  • 无线网络一代比一代要求更高的发送功率
  • 无线电是仅此于屏幕的耗电大户
  • 无线电耗电量是非线性的,这与数据传输模式有关
牢记这一点,移动应用应该以最大限度降低对无线接口的使用为目标。这不是说,你应该完全避免使用网络(the radio);毕竟我们正在创建依赖于网络访问的联网应用!然而,因为保持网络(the radio)激活是如此耗电,所以我们的应用程序应该在网络激活时尽可能多的传输数据,之后尽量不做额外的数据传输。总之,应该避免断断续续传输数据。


尽管WiFi也使用无线电接口来传输数据,但我们应该认识到WiFi的运行机制与2G, 3G, 4G移动网络有根本的不同,认识到这一点是很重要的。相应WiFi的延迟、吞吐量、电量配置也与它们不同。结果是,WiFi和移动网络的网络行为通常是不同的。

使用AT&T Application Resource Optimizer测量电量消耗
尽管都很重视优化电量使用,当目前大多数平台仍然缺乏帮助开发者测量和优化他们的应用的必要工具。谢天谢地,有第三方工具可用,比如由AT&T开发的免费的Application Resource Optimizer(ARO)工具包。
ARO由两部分组成:收集程序和分析程序。收集程序是一个运行在后台的Android应用,它截获发送的数据包,无线电活动,以及与手机的其它交互。为了获得一个使用轨迹,首先加载收集程序,点击记录,然后同你的应用程序进行交互,最后把跟踪记录复制到你的系统中进行分析。
有了跟踪记录之后,你可以使用分析程序打开它,然后就可以一窥你的应用相关的无线电状态、电量消耗、还有流量模式。
分析器的一个伟大功能之一是它为通常的性能陷阱提供建议,比如没有压缩、冗余数据传输等等。
值得注意的两件事情:电池消耗与无线电状态与指定的设备模型和无线网络类型相关。换句话说,数据是基于所用模型中指定的参数进行估计的,而不是对当前所用设备的确切测量。
最后,收集程序只有Android版的,但ARO分析程序能够接受有tcpdump或则其它兼容工具生成的any regular packet trace(pcap)文件

消除周期性和低效率的数据传输


事实上,无论传输的数据量多少,移动无线电都会在一个固定的电量消耗状态与全功率状态之间循环转换,这告诉我们,当谈到电池时,没有所谓的“小请求(small request)”。间隙性的网络访问是反移动网络性能的模式。看 “Inefficiency of Periodic Transfers”。事实上,对该逻辑进行扩展就产生了下面的规则:
  • 移动网络上做轮询是相当昂贵的;尽量不要使用。
  • 尽可能使用推送(push delivery)和通知
  • Outbound和inbound请求应该被合并和聚合
  • 非关键请求应该被推迟到无线电激活时才发送
通常,推送要比轮询更有效率。然而,非常频繁的推送流也会很耗电的。当你需要一个实时更新时,你应该考虑如下问题:
  • 最好的更新间隔是多久,它符合用户的预期吗?
  • 可以使用自适应策略而不是固定更新间隔吗?
  • inbound和outbound请求可以被合并为几个少一些的网络调用吗?
  • inbound和outbound请求可以被推后一点吗?
对于推送(push delivery),能够系统提供的推送服务的本地应用程序(native applications)应该尽量使用。web applications,可以使用server-sent events(SSES)和WebSocket推送来最小化延迟和协议开销。尽可能避免使用轮询和昂贵的XHR技术。

基于自适应间隔,用户偏好,甚至设备的电池电量,一个把多个通知合并为一个推送事件(a single push event)的简单聚合策略,就能够大大改善任何应用程序的电量曲线,特别是常常依赖于这种类型网络访问模式的后台应用。

Nagle算法和高效的服务器推送(Efficient Server Push)
TCP爱好者肯定能认出请求聚合与捆绑建议就是Nagle's算法,不过要把它在应用层重新实现!Nagle算法试图把多个小的TCP消息合并为一个packet以减少协议开销和发送到线上的包的数量。毫不奇怪,我们的移动应用可以从该技术的利用中获益颇多。
该策略的一个简单实现是,在服务端根据时间、数量、大小来聚合消息,而不是有一个消息就触发一次推送。更先进的,显然更具效率的策略是只有在客户端的无线电处于激活状态时才推送更新 -- 例如:推迟消息直到客户端发起一个请求或者利用能够感知客户端无线电状态的第三方服务。
例如,为Android和Chrome提供消息推送APIs的Google Cloud Messaging(GCM),它能够聚合消息,当而且仅当设备激活时推送更新:服务器推送它的消息到GCM,GCM确定最佳的推送时间。
不幸的是,至今没有跨浏览器的API为所有客户端提供像GCM这样的体验。然而,W3C Push API,将来可能会解决这个问题。

间隙性的beacon request,比如audience measurement pings和实时分析(real-time analytic)能够轻易否定所有你细心完成的电池电量优化。这些pings在有线网络中甚至WiFi网络中基本是无害的,但在移动网络上成本巨大。这些beacons(信标?)需要立即发送吗?很可能你可以简单的记录并推迟这些请求直到下一次无线电激活。捎带你的后台pings(Piggyback your background pings),密切关注你代码中第三方库的网络访问模式。
最后,到目前为止我们集中关注电池,由于RRC状态转换,某些技术,比如progressive enhancement和incremental loading,所需的间隙性网络访问还会导致大的延迟。回想一下,在移动网络中,每一个状态转换,都会引起一个高控制面板延迟,这可能带来几百至上千毫秒的额外延迟 。

计算后台更新的能量成本
为了说明轮询对电池寿命的影响,让我们来做一些简单的数学。这些数字不准确,不过一个典型的3G/4G手机大概就在这一范围:
  • 电池容量为5watt-hours,或者18,000焦(5Wh x 3600 J/Wh)
  • 从Idle状态转换为连接状态再回来消耗10焦耳的能量
  • 1分钟间隔轮询每小时消耗600焦耳能量
  • 600焦耳是电池容量的3%
单个应用程序每小时就消耗了可用电池电量的3%!只需要一对非重叠轮询的应用程序就能够在一早上耗干你的电池。公平的讲,一个频繁的、未缓冲更新推送应用程序会有更高的电量消耗。
电池寿命优化和频繁更新是天生的冤家。根据你的应用的需求确定优化策略:bunding of updates,自适应更新间隔,pull vs push,等等。再使用ARO或者类似工具测量影响并做相应调整。

Eliminate Unnecessary Application Keepalives


任何TCP或UDP连接的连接状态和生命周期与设备上的the radio状态都是相互独立的:the radio处于低耗电量状态,同时连接由运营商网络维护。当一个新的来自外部网络的包到达时,运营商无线网络将通知设备,促使它的radio进入连接状态,恢复数据传输。
应用程序不必为了保证连接不被丢弃而始终保持the radio处于"active"状态。不必要的应用保活(keepalives)会对电池寿命性能有巨大的负面影响,而且常常是因为对移动无线网络的工作原理有误解而使用的。Refer to “Physical Layer vs. Application Layer Connectivity” and “Packet Flow in a Mobile Network”

大多数运营商设置了5-30分钟的NAT连接超时。因此,你可能需要一个定期的(5分钟)保活以维持一个连接不被丢弃。如果你发现自己需要更频繁的保活,那就检查你自己的服务器,代理,负载平衡配置。

预期网络延迟开销(Anticipate Network Latency Overhead)


在一个移动网络中,单个HTTP请求,总是会带来几百到几千毫秒的网络延迟开销。部分是由于高往返延迟导致的,但我们要记住还有DNS、TCP、TLS开销(图8-2),以及控制面板成本!

       

最好的情况是,the radio已经处于激活状态(in a high-power state),DNS已经预解析好,也有一个可用的TCP连接:客户端可能能够利用一个现有连接,从而避免创建一个新的连接的开销。然而,如果连接处于忙碌状态,或者根本不存在,那我们就不得不引入一系列的额外往返延迟,之后才能发送应用数据。
为了说明这些额外网络延迟的影响,让我们做一个乐观的假设,4G网络RTT为100ms,3.5G网络RTT为200ms:


在一个3G网络中,为重新创建一个radio上下文,RRC控制面板(control-plane)延迟单独添加了几百到几千毫秒的开销!一旦radio激活,我们可能需要解析主机名为IP地址,然后执行TCP握手 -- 两次网络往返。如果需要一个安全通道,我们可能还需要另外两次网络往返(see “TLS Session Resumption”)。最后,可以发送HTTP请求了,这增加至少另外一个往返。
我们还没有考虑服务器响应时间或响应大小,这可能需要多次往返,而我们已经引入了半打往返延迟了。往返次数乘以往返时间,我们看到3G网络的延迟开销超过了1秒,4G网络有大约半秒。

考虑RRC状态转换 (Account for RRC State Transitions)


如果移动设备已经空闲了几秒钟,你应该假定和预期第一个数据包将招致几百,甚至上千毫秒的额外RRC延迟。一般说来,4G网络增加100ms,3.5G增加150 - 500ms,3G网络增加500 - 2500ms,这是一次性的控制面板成本。
RRC是专门设计来帮助减少操作耗电的radio的成本的。然而,由于各种各样的计时器(the various timers),计数器(counter),必需的网络协商以及不同的radio状态转换产生的开销的存在,我们节约的电池电量很容易被延迟的增加和低吞吐量抵消掉。虽然如此,RRC在移动网络中也是一个不争的事实 -- 没有其它的办法 -- 如果你想为mobile web创建优化的应用,你在设计时必须把RRC牢记于心。
快速总结下我们已经了解的RRC:
  • 不同的无线标准的RRC状态机是不一样的
  • RRC状态机由设备的the radio网络管理
  • 当有数据必须发送时,RRC状态提升至大功率状态
  • 超过了网络配置的超时时间后,RRC状态降至低功耗状态
  • (4G)LTE状态转换花费10 - 100ms
  • (4G)HSPA+状态转换花费与LTE相当
  • (3G)HSPA和CDMA状态转换可能花费几秒
  • 每次网络传输,无论大小是多少,耗费的能量都是一样的(incurs an energy tail)
我们已经讨论了为什么省电对移动应用程序是一个多么重要的目标,我们还重点讨论了低效率和间歇性传输的坏处,那是超时驱动的RRC状态转换的直接结果。然而,还有一件事情你需要记住:如果设备radio已经空闲了(Idle),那在移动网络中初始化一次新的数据传输将会导致一个额外的延迟,如前所述,这个花费从最新一代网络的100ms到3G和2G网络的几秒。
在应用程序看来,网络总是在线,不过那是一个幻觉,由RRC控制的物理层或者radio层持续不断的连接、断开连接。表面看来,这不是一个问题,但许多不知道其中缘由的用户,其实很容易注意到这种由RRC附带的延迟。

从网络通信中解耦用户交互(Decouple User Interactions from Network Communication)


一个设计良好的应用感觉会很快,这是通过提供即时反馈,即便在当前连接很慢或者请求需要花很久才能完成的情况下,来达到的。不要把用户交互、用户反馈和网络通信耦合在一起。为了提供最好的用户体验,应用程序应该在几百毫秒内确认用户输入。see “Speed, Performance, and Human Perception”.
如果需要一个网络请求,那就在后台初始化它,并提供即时UI反馈确认用户输入。单独的控制面板时延往往会推动你的应用程序为提供即时用户反馈分配预算。要考虑高延迟的情况 -- 你不能消除由核心网络和RRC附带的延迟 -- 确保你的设计团队在设计应用时意识到这些限制的存在。

可变网络接口可用性设计(Design for Variable Network Interface Availability)


用户不喜欢迟钝的应用,但因为“暂态网络错误”而奔溃的应用程序,才是最糟糕的体验。你的移动应用在面对通常的网络失败时应该足够健壮:主机不可达,突然下降的吞吐量或延迟增加,抑或连接的直接损失。不像有线网络世界,你不能简单的假定连接一旦创建,它就一直在那。用户可能在移动,可能进入一个干扰严重,或有很多激活用户,或者覆盖不佳(plain poor coverage)的区域。
此外,就像你设计网页时不能只考虑最新的浏览器一样,你设计应用时也不能只考虑最新一代的网络。如我们之前所述(“Building for the Multigeneration Future”),即便手握最新的手机,你也得不断的在4G, 3G, 设置2G网络间转换,因为无线网络环境变化多端。你的应用程序应该订阅(subscribe)这些接口转换,并做相应调整。

在移动网络唯一不变的就是变换。广播通道的质量基于与信号塔之间的距离,与附近用户的冲突,周围环境的干扰,还有其它很多因素,它总在不断的变化。考虑到这一点,对带宽和延迟做各种形式的估计以优化应用程序可能颇令人心动,不过我们应该,也最好是把估计的结果,看做是瞬时数据。

iPhone 4“天线门”事件是一个说明radio性能的不可预测性的极好的例子:接收质量受你手持姿势影响,这就是臭名昭著的“你拿错了。”

移动网络上的延迟和带宽估计在几十毫秒到数百毫秒,至多1秒之内是稳定的,不能再长了。因此,像自适应比特流这样的优化对于长期实时流是很有用的,比如视频,采取的做法是,缓冲几秒钟的数据块,这些带宽估计肯定不能够缓存起来或用于将来确定可用吞吐量:即使在4G网络上,可能你刚测得的吞吐量是几百Kbit/s,然而你移动了几英寸之后,速度立马就提升至Mbit/s。

移动网络上的流媒体应用


移动网络上的流媒体应用是一个棘手的问题。如果你需要执行大量下载并且确信整个文件都会被用到,那么你应该一次性把整个文件下载下来,然后让radio进入Idle状态,越长越好。
然而,如果因为文件太大,或用户限制你不能下载整个文件,那你应该采用自适应比特流,持续调整以适应网络吞吐量的不断变化。你将付出高昂的电池成本,不过这样做至少提供了最好的用户体验!另外,你应该要提示用户打开Wifi。
端到端的带宽和延迟估计在任何网络上都是一个困难的问题,在移动网络上就更甚了。不要去估计,因为你得到的结果是错的。相反,你应该使用关于这一代网络的粗粒度信息,并相应的调整你的代码。更清楚的讲,知道网络的类型并不能对端到端的性能做任何保证,它只能告诉你关于第一个无线跳的延迟和运营商网络的端到端性能的重要数据。see“Latency and Jitter in Mobile Networks” and Table 7-6.
最后,除了吞吐量和延迟外,你还应该考虑连接丢失:假定这种情况经常发生,而不是当做例外。当网络不可用或发生一个暂时性的错误时,你的应用程序应该最大限度保持运行,并基于请求的类型和特定的错误做出合适的响应:
  • 不要缓存和猜测网络状态
  • 分派请求,监听失败,诊断发生了什么
  • 暂态性错误将会发生;做好应对计划,使用恢复策略
  • 监听连接状态,预测最好的请求策略
  • 对请求重试使用退避算法;不要使用永久自旋
  • 如果掉线了,记录并在之后可能的时候分派请求
  • 利用HTML5 AppCache和localStorage实现离线模式

Burst Your Data and Return to Idle


移动无线接口被优化用于突发性传输,你应该尽可能的利用这一性质:把你的请求组合在一起,尽可能多的下载,越快越好,然后让radio返回到Idle状态。这一策略将会带来最好的网络吞吐量并最大限度延长设备电池寿命。

最精确的估计网络速度的方式,就是使用它!最新一代的网络,比如LTE和HSPA+,以一毫秒的时间间隔动态分配资源,并优先考虑突发性数据流。要快,很简单:批处理或预取尽可能多的数据,然后让网络休息。

一个重要的推论是,渐进式的资源加载(progressive loading of resources)对移动网络可能弊大于利。如果一小块一小块的下载内容,我们的应用程序就面临更高的吞吐量和延迟波动,更别提更高的用于操作radio的能源成本了。解决方法是,预测用户下一步所需要的,提前下载下来,让后让the radio进入Idle状态。
  • 如果你需要获取一个大的音乐或视频文件,考虑提前把整个文件下载下来,而不是一块一块慢慢下载。
  • 预期应用内容,创建指标和统计模型,以帮助识别哪些内容适合提前下载。
  • 提前预期第三方内容,比如广告,并在需要的时候添加应用逻辑展示和更新它们的状态。
  • 消除不必要的间歇性传输,see   “46% of Battery Consumption to Transfer 0.2% of Total Bytes”.

Offload to WiFi Networks


当前的行业估计显示几乎90%的全球无线通信源于室内,常常是有Wifi连接的区域(说明大部分手机流量是在有Wifi的情况下产生的)。最近的4G网络在延迟和吞吐量方面与Wifi相当,不过你知道,营运商仍然很大可能会限制月流量:移动网络访问对用户来讲还是很贵。此外,Wifi连接的电池效率更高(see “3G, 4G, and WiFi Power Requirements”),因为大数据传输不需要一个RRC。
任何时候,特别是当你正在创建一个数据密集型应用,你都应该尽可能的利用Wifi连接,如果Wifi是关闭的,你应该考虑提示用户打开Wifi,这样可以改善体验和降低成本。

应用协议或应用最佳实践


我们的网络基础设施的层次架构的一个伟大性质是,它对传输层抽象了物理载体,传输层为应用协议抽象了路由和数据传输。这种层次分离提供了良好的API抽象,但为了最好的端到端性能,我们仍然需要考虑整个协议栈。
在本章,我们讨论了移动网络物理层的独特性质,例如,RRC的存在,设备的电池寿命问题,移动网络的路由延迟问题。然而,在前面的几章中,我们已经讨论了在物理层之上 传输和会话协议,它们优化也是一样重要的,甚至更加重要。 
重用长连接最小化延迟,地理定位靠近客户端的服务器和数据,TLS部署优化,以及我们之前强调的所有其它优化,它们在RRT很高,带宽很珍贵的移动网络更为重要。
当然,我们的优化策略不会止步于传输和会话协议;它们只是基础。此外,我们必须同时考虑不同的应用协议(HTTP 1.0, 1.1 和 2.0)对性能的影响,还有web应用最佳实践 -- 继续往下读,我们还没完呢。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章