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