网络协议的性能
如今轮到我们实际上能够控制的东西了。
网络处理的性能与延迟时间的添加是不成比例的。这是因为大多数网络协议的内在操作是双向信息交换。
本章的其余部分则側重于理解为什么会产生这些信息交换以及怎样降低甚至消除它们交换的频率。
图3:网络协议
传输控制协议
传输控制协议(TCP)是一种面向连接、基于ip的传输协议。TCP影响下的无差错双工通信信道对其它协议如HTTP或TLS来说都不可缺少。
TCP展示了很多我们须要尽量避免的双向通讯。这当中一些能够通过採用扩展协议如TCP Fast Open协议来替代;还有一些则能够通过调整系统參数来达到最小化,比方初始化拥塞窗体。在本节中,我们将探讨这两种方法同一时候也提供一些TCP内部组件的背景。
TCP Fast Open
初始化一个TCP连接约定须要3次信息交换,也就是我们所说的3次握手。
TCP Fast Open(TFO)是TCP的一个扩展,它消除了通常握手过程中的往返延迟。
TCP在client和服务端的三次握手协商操作參数使得两方做健壮的双向通信称为可能。最開始的SYN信息(同步信息)代表client的连接请求;假设服务端接受这个请求,那么它将返回一个SYN-ACK消息(同步和接受消息);最后。client发送一个ACK消息来应答server。这时,一个逻辑连接就已经建立完毕,client就能够发送数据了。这当中你假设注意到,3次握手过程中至少引入了一个RTT的延迟那就非常好了。
图4:TCP3次握手
从传统角度来看。除了对连接进行回收利用外没有其它方法来避免TCP3次握手造成的延迟。然而,这样的想法发生随着Tcp Fast Open IETF规范的引入发生了变化。
TFO同意client在逻辑连接建立之前就開始发送数据。这实际上否定了3次握手中的往返延迟。这样的优化的累积效应是让人印象深刻。依据谷歌的调查,TFO能够降低页面40%的载入时间。尽管这个规范仅仅是草案,可是TFO已经被主流浏览器(Chrome22以上)和平台(Linux3.6以上)所支持,而且其它供应商也保证将在不久以后会全然支持它。
TCP Fast Open是对3次握手协议的一个修正,它同意在同步消息(SYN Message)内有少量的数据负载(如HTTP请求)。
这个有效负责会传递给应用server,否则连接握手完毕。
早些时候扩展方案像TFO终于因安全问题而失败。而TFO通过使用安全令牌或者cookie来解决问题。也就是说在传统的TCP连接握手过程中给client分安全令牌(tooken),而且期望将安全令牌包括在TFO优化请求的SYN消息中。
对于TFO的使用,这里有一些小的警告。
当中最值得注意的是,在初始化的SYN消息中请求的数据缺乏幂等性保证。尽管TCP保证反复数据包(反复常常发生)会被接受者忽略。可是这个保证并不适用于连接的握手过程。
眼下在规范草案中正在标准化这个解决方式,可是于此同一时候TFO仍然能够被安全的应用于幂等性处理。
初始拥塞窗体
初始拥塞窗体是TCP的一个可配置项而且有巨大的潜在能力来加速小的网络事务。
近期的IETF规范促进通常的初始拥塞窗体的设置增长到3个报文段(如数据包)到10个报文段。这个建议是基于谷歌进行的广泛研究,这个研究证明了这个參数的设置对性能有平均10%的提升。
但假设不介绍TCP的拥塞窗体(cwnd)的话。这样的设置的目的和潜在影响就不会被真正领会。
当在一个不可靠的网络上进行操作时,TCP来保证client和服务端的可靠性。这相当于一个承诺,全部发送出去的数据都会被接收到,或者至少看起来是这样。当中,包丢失是满足可靠性要求的最大障碍。这须要侦測、纠错以及预防。
TCP採用一个肯定应答机制来检測丢包情况。即每一个发送出去的包都应该被它预定的接收方应答,假设没有应答就意味着这个包在传输过程中丢失。
在等待确认的过程中,数据传输包保存在一个特殊的缓冲区中,也就是所说的拥塞窗体。当这个缓冲区被塞满时,一个被称作cwnd耗尽的事件发生,全部传输停止,直到接收方应答后腾出有效空间来发送很多其它的数据包。
这些事件在TCP性能中至关重要。
除了网络带宽的限制,TCP吞吐量根本上受cwnd耗尽事件发生频率的限制。而这可能与拥塞窗体的大小有关。
当TCP性能达到峰值时须要一个拥塞冲口来调节当前的网络状态:拥塞窗体过大将添加网络阻塞的风险--过度拥堵的网络状况会添加大量包丢失;过小则珍贵的网络带宽将不能充分被利用。
从逻辑上讲,对网络情况了解的越多,肯能越能选择一个最佳的拥塞窗体大小。
实际情况则是,关键网络属性比方容量和延迟,是非常难衡量的并且不断在变化。
并且,假设一个基于互联网的TCP连接须要穿过很多网络的这又会是一件更加复杂的事情。
因为缺乏手段来准确确定网络容量大小,相反TCP通过网络拥堵情况来判断拥塞窗体大小。
当TCP发现有包丢失时它就会扩大拥塞窗体的大小,提示下行某处有一个网络无法处理当前的传输速率。
通过採用这样的拥塞避免机制,TCP终于最小化cwnd耗尽事件在某种程度上它消耗完为全部连接所分配的容量。那么如今,终于,我们也达到了目的。解释清楚了初始拥塞窗体參数的重要性。
网络拥堵情况仅仅能通过丢包測试来检測。
一个新的或者空暇的连接因为没有足够丢包数据来证明创建拥塞窗体的最佳大小。TCP採用了一个比較明智的做法就是以一个可能最小情况导致网络拥堵的大小一開始作为拥塞窗体大小。这最初意味着须要设置1个分片(大约1480字节),并且有些时候这样的做法是推荐的。而稍后的实验会演示一个高达4的设置也是有效的。在实践中你也通常发现初始拥塞窗体设置为3报文段(大约4kb)。
初始拥塞窗体不利于小的网络事务处理。这样的效果非常easy说明。在表中的3个报文段设置下。在发送3个数据包或者4k的数据后cwnd耗尽时间就会发生。如果数据包是连续发送的,响应的响应不会在不论什么所同意的往返时间(RTT)之前到达;假如RTT是100ms的话,那么有效传输速率仅仅有可怜的400字节/秒。虽然TCP会调节自身的拥塞窗体来充分利用有效容量,可是它在一開始将会非常慢。其实,这样的方式被称为慢启动。
为了降低慢启动对较小的下载的性能影响,它须要又一次评估初始拥塞窗体的风险回报。谷歌正是这样做的,并且发现将初始拥塞窗体设置在10个报文段(约14kb)会在最小网络拥堵情况下达到最大吞吐量。现实世界中也证明了这样设置总共能够降低页面10%的载入时间;连接的往返延迟将得到更大的改善。
改动初始拥塞窗体的默认值也并非那么简单的。在大多数server操作系统下,一个系统级的配置仅仅有有特权的用户才可设置;这个參数也非常少甚至不能被没有权限的应用在client配置。须要注意的是一个更大的初始拥塞窗体在server端能够加速下载,而在client则能够加速上传。假设无法在client改变这个设置就意味着应该特别努力去降低请求负载的大小。
超文本传输协议
本节将讨论在超文本传输协议(HTTP)性能方面来降低高的往返延迟的技术。
KeepAlive
KeepAlive是一个HTTP约定来同意同步连续的HTTP请求来使用同一个TCP连接。
至少一个单组往返请求所须要的TCP的3次握手能够避免,每次请求能够节省几十或者几百毫秒。更深层次的,keepalive另一个额外的可是未被提及的优点就是它在各个请求之间保留了当前TCP的拥塞窗体大小,这将导致更少的cwnd耗尽事件发生。
图5:HTTP pipelining
实际上,管道使网络延迟分布于网络往返的各个HTTP事务中。
比如,5个管线式的HTTP请求通过一个100毫秒的RTT连接时将产生一个平均20毫秒的往返延迟;在相同条件下。10个管线式请求时这个平均延迟将降低到10毫秒。
可是,HTTP pipeling有明显的缺点阻止了它被广泛使用,即历史上參差不齐的HTTP代理支持和拒绝服务攻击的影响。
安全传输层协议
传输层安全性(Transport Layer Security,TLS)是一个面向会话的网络协议同意在公共网络安全地交换敏感信息。尽管TLS在安全通信方面卓有成效。可是在高延迟网络下它的性能会下降。
TLS採用一个复杂的握手协议包含两次交换client-服务端信息。一个TLS安全的HTTP传输明显比較慢也正是这个原因。通常。发现一个TLS慢实际上是在抱怨它的握手协议中多重往返所产生的延迟。
图6:DNS查询
通常,主平台提供了缓存实现来避免频繁的DNS查询。DNS缓存的语义很easy:每一个DNS响应包括一个存活时间(time-to-live,TTL)属性来声明结果会被缓存多长时间。TTL的范围通常在几秒钟到几天之间,但通常为几分钟。
很低的TTL值。通常在一分钟下面,被用在影响负载分配或者降低server替换或ISP故障转移的时间。
刷新失败
高可用系统通常依赖于他们IP机房的冗余基础设施主机。
TTL值较小的DNS条目能够降低客户指向失败主机的时间,可是同一时候会导致大量额外的DNS查询。所以说,TTL的值应该是降低停机时间和client性能最大化的一个折中。
通常减少client性能是没有意义的。但当server故障时是个例外。有一个简单的方法来解决问题,也就是说不是严格的遵守TTL,而是只当更高层协议如TCP或HTTP检測到不可恢复错误时才刷新DNS缓存。
这样的技术在大多数场景下模拟TTL保持DNS缓存一致的行为。然而这差点儿消除了不论什么基于DNS高可用性解决方式中的性能损失。
可是须要注意的是这个技术方案和其它基于DNS的分布式负载方案不兼容。
异步刷新
异步刷新是一个DNS缓存方法,它遵守已经设置TTL规则可是在非常大程度上消除了频繁查询DNS的延迟。在这项技术中,须要一个异步DNSclient库如c-ares来实现。
这种方法非常easy。一个过期的请求仍然返回的是老的结果,可是后台有一个非堵塞的DNS查询来定时刷新DNS缓存。这样的方案假设採用堵塞式(如同步)回调来查询每条老的DNS数据,那么这个方法差点儿不受DNS查询延迟的影响,可是仍然和非常多基于DNS的故障转移方案以及分布式负载方案兼容。
总结
要降低移动网络高延迟的影响就须要通过降低使移动网络延迟急剧添加的网络往返次数来实现。而採用软件优化专注于最大限度地降低或消除往返协议的消息是克服这项艰巨的性能问题的关键。
(移动网路性能篇,全文完。)
1. 本文由程序猿学架构翻译
2. 本文译自The Performance of Open Source Software | Secrets of Mobile Network Performance
3. 转载请务必注明本文出自:程序猿学架构(微信号:archleaner )
4. 很多其它文章请扫码: