《Web性能权威指南》笔记

序言

最近因为过生日,公司可以替每个过生日的员工买本书,我选择了这本《Web性能权威指南》,因为我觉得作为一个Web开发者,没有系统的学习过一本Web相关的书籍,大部分都是Java相关书籍。虽然不知道学了这有多少用,学完能记住多少,但是我觉得去学习这多少会有点用,巩固一下知识点也好。像序言里说的“墙上芦苇,头重脚轻根底浅”,只知表面上的东西很难在发生异常状况解决突发问题。理解基础知识很重要。最后还是很感谢公司赠送的生日礼物。

第一章 延迟与带宽

WPO(Web Performance Optimization,Web性能优化)产业的诞生证明用户越来越重视速度方面的体验,而对所有网络通信都有决定性影响的两个方面则是延迟带宽

  • 延迟(delay):分组从信息源发送到目的地所需的时间。
  • 带宽(bandwidth):逻辑或者物理通信路径最大的吞吐量。

其中,ISP(Internet Service Provider)指的是互联网服务提供商。

《Web性能权威指南》笔记_第1张图片

延迟

延迟是消息或分组从起点到终点经历的时间。但很多因素可能影响传送消息的时间:

  • 传播延迟:消息从发送端到接收端需要的时间,是信号传播距离和速度的函数。
  • 传输延迟:把消息中的所有比特转移到链路中需要的时间,是消息长度和链路速度的函数。
  • 处理延迟:处理分组首部、检查位错误及确定分组目标所需的时间。
  • 排队延迟:到来的分组排队等待处理的时间。

应用一般必须在几百毫秒之内响应。CDN(Content Delivery Network,内容分发网络)就是可以大幅降低传播分组的时间的,前面的文章也提到过。

traceroute命令可以查看服务商拓扑结构和速度,如下,从某一跳到另一跳都是ms级别。 traceroute是简单的网络诊断工具,可以列出分组经过的路由节点,以及它在IP网络中每一跳的延迟。为找到每一跳的节点,它会向目标发送一系列分组,每次发送时的“跳数限制”都会递增。在达到跳数限制时,中间的节点会返回ICMP Time Exceeded消息,traceroute根据这个消息可以计算出每一跳的延迟。

《Web性能权威指南》笔记_第2张图片

带宽

光纤就是一根“光导管”专门用来传输光信号;而金属线则用来传输电信号,电信号传输信号损失、电磁干扰大,同时维护成本也较高。这两种线路我们的数据分组很可能都会经过,但长距离的分组传输都是通过光纤完成的。

通过波分复用(WDM,Wavelength-Division Multiplexing)技术,光纤可以同时传输很多不同波长的光。一条光纤连接的总带宽=每个信道的数据传输速率*可复用的信道数。

构成因特网核心数据路径的骨干或光纤连接,每秒能够移动数百太比特信息。然而,网络边缘的容量就小得多了,而且很大程度上取决于部署技术,比如拨号连接、DSL、电缆、各种无线技术、光纤到户,甚至与局域网路由器的性能也有关系。

目标

目标即高带宽和低延迟。

如何提高带宽?目前视频流量已经占据全部因特网流量的一半以上。我们可以在光纤链路中部署更多光纤、在拥塞的路由之间铺设更多线路,甚至是改进WDM技术,以便让现有连接能够传输更多数据。不过,任何介质超过一定限度都会出现性能递减效应。

针对延迟采取优化措施,就必须从设计和优化协议及应用着手,并且时刻牢记光速的限制。可以减少往返、把数据部署到接近客户端的地方,以及在开发应用时通过各种技术隐藏延迟。

第二章 TCP的构成

因特网有两个核心协议:

  • IP(Internet Protocol):属于网络层,负责联网主机之间的路由选择和寻址。
  • TCP(Transmission Control Protocol)。属于传输层,负责在不可靠的传输信道之上提供可靠的抽象层。

TCP/IP也常被称为“因特网协议套件”(Internet Protocol Suite)。最早的建议(RFC 657)经过几次修订,于1981年作为TCP/IP标准第四版发布。发布时并不是一个标准,而是两个独立的RFC:

  • RFC 791——Internet Protocol;
  • RFC 793——Transmission Control Protocol。

三次握手

三次握手、四次挥手我们计算机网络中都学过。这里也算是巩固一遍知识点。 

具体流程:

  • SYN:客户端选择一个随机序列号x,并发送一个SYN分组,其中可能还包括其他TCP标志和选项。
  • SYN ACK:服务器给x加1,并选择自己的一个随机序列号y,追加自己的标志和选项,然后返回响应。
  • ACK:客户端给x和y加1并发送握手期间的最后一个ACK分组。

三次握手完成后,客户端与服务器之间就可以通信了。客户端可以在发送ACK分组之后立即发送数据,而服务器必须等到接收到ACK分组之后才能发送数据。这个启动通信的过程适用于所有TCP连接,因此对所有使用TCP的应用具有非常大的性能影响,因为每次传输应用数据之前,都必须经历一次完整的往返。

三次握手带来的延迟使得每创建一个新TCP连接都要付出很大代价。所以提高TCP应用性能的关键就在于重用连接。

TFO(TCP Fast Open,TCP快速打开)就是致力于减少新建TCP连接带来的性能损失。谷歌研究人员发现TFO平均可以降低HTTP事务网络延迟15%、整个网页加载时间10%以上。

拥塞预防及控制

拥塞控制是复杂网络中众所周知的一个问题。IP数据报协议和TCP传输层协议在一起使用时,由于传输层和数据报层之间的交互会导致一些不常见的拥塞问题。特别是IP网关容易受到“拥塞崩溃”的严重影响,尤其是在网关连接不同带宽的网络时...

可能是往返时间超过了所有主机的最大中断间隔,于是相应的主机会在网络中制造越来越多的数据报副本,使得整个网络陷入瘫痪。最终,所有交换节点的缓冲区都将被填满,多出来的分组必须删掉。目前的分组往返时间已经设定为最大值。主机会把每个分组都发送好几次,结果每个分组的某个副本都会抵达目标。这就是拥塞崩溃。

这种情况永远存在。达到饱和状态时,只要选择被删除分组的算法适当,网络就可以退而求其次地持续运行下去。这里其实和缓存淘汰策略、线程池拒绝策略有点类似,当缓存区满、内存满、线程池满的时候退而求其次让其能继续正常工作,保证可用性。

为解决拥塞问题,TCP加入很多机制,以便控制双向发送数据的速率,比如流量控制拥塞控制拥塞预防机制

流量控制

流量控制是一种预防发送端过多向接收端发送数据的机制。为实现流量控制,TCP连接的每一方都要通告自己的接收窗口(rwnd,Receiver Window),其中包含能够保存数据的缓冲区空间大小信息。

两端都会使用自身系统的默认设置来发送rwnd。如果其中一端跟不上数据传输,那它可以先向发送端通告一个较小的窗口,假如窗口为零,则意味着必须由应用层先清理缓冲区,才能再接收剩余数据。这个过程贯穿于每个TCP连接的整个生命周期:每个ACK分组都会携带相应的最新rwnd值,以便两边动态调整数据流速,使之适应发送端和接收端的容量及处理能力。

窗口缩放(Window Scaling)—— RFC 1323

最初TCP规范分配给通告窗口大小的字段是16位的,相当于窗口最大值65535字节。但经常无法获得最优性能,特别是在“带宽延迟积”较高的网络中。为解决这个问题,RFC 1323标准提供了“TCP窗口缩放”选项,可以把接收窗口大小由65535字节提高到1G字节。缩放TCP窗口是在三次握手期间完成的。

TCP窗口缩放机制在所有主要平台上都是默认启用的。不过,中间节点和路由器可以重写,甚至完全去掉这个选项。如果我们的服务器或客户端连接不能完全利用现有带宽,那么可以查一下窗口大小。

Linux中,可以通过下列命令检查和启用窗口缩放选项:

  • sysctl net.ipv4.tcp_window_scaling
  • sysctl -w net.ipv4.tcp_window_scaling=1

其中,sysctl命令可以参看:sysctl命令_Linux sysctl 命令用法详解:时动态地修改内核的运行参数

慢启动

1988年,Van Jacobson和Michael J.Karels为解决数据在某个中间网关堆积而导致分组被删除降低网络传输效率的问题,将慢启动、拥塞预防、快速重发和快速恢复几种算法写入TCP规范中。

慢启动方案是在分组被确认后增大窗口大小,慢慢地启动。cwnd(拥塞窗口)为发送端对客户端接收确认(ACK)之前可以发送数据量的限制,初始化时设置为系统设定的保守值(Linux中即initcwnd)。

TCP连接传输的最大数据量取rwnd(接收窗口)和cwnd(拥塞窗口)中的最小值,而服务器实际上可以向客户端发送4个TCP段,然后就必须停下来等待确认。此后,每收到一个ACK,慢启动算法就会告诉服务器可以将它的cwnd窗口增加1个TCP段。每次收到ACK后,都可以多发送两个新的分组。TCP连接这个阶段称为“指数增长”阶段,因为客户端和服务器都在向两者之间网络路径的有效带宽迅速靠拢。

《Web性能权威指南》笔记_第3张图片

包括HTTP在内的很多应用层协议都运行在TCP协议之上,无论带宽多大,每个TCP连接都必须经过慢启动阶段。不可能一上来就完全利用连接的最大带宽!

客户端与服务器之间的往返时间和初始拥塞窗口大小的函数(cwnd大小达到N所需的时间):

  • 时间 = 往返时间 \times \left \lceil log_{2}(\frac{N}{init cwnd}) \right \rceil

慢启动会导致客户端与服务器之间经过几百毫秒才能达到接近最大速度的问题,对于大型流式下载服务的影响倒不显著,因为慢启动时间可以分摊到整个传输周期内消化掉。但对于HTTP连接,特别是短暂、突发的连接来说,常常会出现还没达到最大窗口请求就被终止的情况。也即很多Web应用的性能经常受到服务器与客户端往返时间的制约。

慢启动重启

除了调节新连接的传输速度,TCP还实现了SSR(Slow-Start Restart,慢启动重启)机制。这种机制会在连接空闲一定时间后重置连接的拥塞窗口。道理很简单,在连接空闲的同时,网络状况也可能发生了变化,为了避免拥塞,理应将拥塞窗口重置回“安全的”默认值。

然而SSR对那些会出现突发空闲的长周期TCP连接(比如HTTP的keep-alive连接)有很大影响。因此建议在服务器上禁用SSR。在Linux平台,可以通过下列命令检查和禁用SSR:

  • $> sysctl net.ipv4.tcp_slow_start_after_idle
  • $> sysctl -w net.ipv4.tcp_slow_start_after_idle=0

通过实际对比可以很明显的发现,没有三次握手慢启动,性能会大幅度提升,这也就是后面会有keep-alive、流水线和多路复用的优化。RFC 6928为了提升用户体验和TCP应用性能增大TCP的初始拥塞窗口(IW10,10段)。

拥塞预防

TCP调节性能主要依赖丢包反馈机制。如前面一图分组丢包指数增长时,由于拥塞预防算法的介入,分组丢包成倍减少。拥塞预防算法把丢包作为网络拥塞的标志,即路径中某个连接或路由器已经拥堵了,以至于必须采取删包措施。因此,必须调整窗口大小,以避免造成更多的包丢失,从而保证网络畅通。

TCP比例降速

确定丢包恢复的最优方式并不容易。太激进会间歇性丢包,不够快也会造成更多的分组丢失。最初TCP使用AIMD(Multiplicative Decrease and Additive Increase,倍减加增)算法,后面RFC 6937采用的新算法PRR(Proportional Rate Reduction,比例降速),新算法因丢包造成的平均连接延迟减少了3%~10%。

带宽延迟积

TCP内置的拥塞控制和预防机制对性能还有另一个重要影响:发送端和接收端理想的窗口大小,一定会因为往返时间及目标传输速率而变化。

发送端和接收端之间在途未确认的最大数据量,取决于拥塞窗口(cwnd)和接收窗口(rwnd)的最小值。接收窗口会随每次ACK一起发送,而拥塞窗口则由发送端根据拥塞控制和预防算法动态调整。

BDP(Bandwidth-delay product,带宽延迟积):数据链路的容量与其端到端延迟的乘积。这个结果就是任意时刻处于在途未确认状态的最大数据量。BDP是往返时间和目标传输速度的函数。因此,往返时间不仅在高速传输延迟中是一个常见的瓶颈,就算在LAN中也可能是一个瓶颈。

针对TCP的优化建议

TCP是一个自适应的、对所有网络节点一视同仁的、最大限制利用底层网络的协议。这章只是蜻蜓点水式地介绍了影响TCP性能的几个典型因素:

  • TCP三次握手增加了整整一次往返时间。
  • TCP慢启动将被应用到每个新连接。
  • TCP流量及拥塞控制会影响所有连接的吞吐量。
  • TCP的吞吐量由当前拥塞窗口大小控制。

服务器配置调优:

  • 增大TCP的初始拥塞窗口——加大初始拥塞大小可以让TCP在第一次往返就传较多数据
  • 慢启动重启——连接空闲时禁用慢启动
  • 窗口缩放——启动窗口缩放可以增大最大接收窗口大小。
  • TCP快速打开(TFO,TCP Fast Open)——某些条件下允许第一次SYN分组中发送应用程序数据。

应用程序行为调优:

  • 能少发就少发
  • 让数据传输的距离更短
  • 重用TCP连接

性能检查清单:

  • 把服务器内核升级到最新版本;
  • 确保cwnd大小为10;
  • 禁用空闲后的慢启动;
  • 确保启动窗口缩放;
  • 减少传输冗余数据;
  • 压缩要传输的数据;
  • 把服务器放到离用户近的地方以减少往返时间;
  • 尽最大可能重用已经建立的TCP连接。

你可能感兴趣的:(通信,基础,java)