网络协议优化

影响网络的因素

  • 网络环境
  • 客户端配置
  • 页面自身,大小和元素复杂度
  • 网络协议

直接和页面相关的页面大小,页面的元素类型的多少,也就是说一个页面越大,元素越多,动态的交互越频繁,那相应的性能可能就会受到更大影响。页面优化问题也是前端优化的主战场。

网络环境以及端配置,包括用户手机硬件的性能、软件的操作系统版本,也会对性能产生影响。而这两个主要和运营商以及用户的配置有关,也是我们很难施加影响的一部分。

针对1.1的优化

问题

  • 单链路串行:一个TCP链路上,如果有多个请求,则每个请求都只能一个接着一个发送
  • 头部未压缩:移动环境下,上行带宽是相当的慢的,只有下行的1/10或更少

优化

增加并发连接数

具体措施:单域名多TCP链接多域名,域名分片

单域名多TCP链接由于存在队头阻塞的问题,它只能通过提升并发连接的数量来提升用户的访问性能。并不是真正意义上的并发请求。

域名分片其实可以做到并发请求,但是也造成了每个域名的请求都要建立连接。

减少请求
  • 缓存
  • CSS Sprite
  • data uri
  • 图片内联

HTTPS VS HTTP

最坏情况下,HTTPS要比HTTP多出7个RTT。

TLS握手有2个阶段

  • 完全握手阶段一:协商协议版本、密码套件、请求证书、校验证书。
  • 完全握手阶段二:协商对称密钥,即非对称密钥交换计算

在阶段一中,校验证书时,可能还需要校验证书的状态,因为有可能存在主动撤销证书的情况,证书的匙钥也有可能被泄露或者说 CA 被攻击,所以查询证书状态是必要的。

查询证书状态就是OCSP,OCSP需要跟CA完成DNS交互、TCP交互和OCSP请求,所以整个过程就有3次的RTT。

未经优化的https,RTT会增加7个,同时还有其他的耗时,证书校验、密钥计算、内容对称的加解密等计算,这些都严重影响https的性能。

TCP & TLS优化

TCP优化 —— TFO(TCP FAST OPEN)

TCP的最大问题是通信前都需要进行三次握手,而TFO的出现就是为了干掉握手的RTT。

它的具体操作是:首次通信还是需要做三次握手,不同的是,这时服务器在返回SYN+ACK的时候,会同时带上一个cookie。这个cookie会中止在客户端,后面再需要TCP链接时,端上发出SYN包的同时将会带上cookie,然后直接带上http数据,这样,在 SYN 包发出的同时将应用层数据一起发出来,减少了一个RTT对性能的影响。

TCP优化需要操作系统的支持,需要 IOS9+ 或者 linux kervel3.7+,并且不支持 Windows 系统。因此这个实施的成本比较高。

TCP优化 —— 窗口设置

接收窗口/滑动窗口(rwnd)

在传输数据时,如果发送方传输的数据量超过了接收方的处理能力,那么会出现丢包的问题。为此,需要通过控制通信双方在通信过程中的窗口大小,用来确定最大能处理的数据。如果窗口衰减到0,则表示不能再接收了。

rwnd只是控制接收方的过载问题,但是却不能反映整个网络是否过载的情况。

慢启动/拥塞窗口(cwnd)

为了避免网络过载,引入cwnd,表示发送方最大允许传输的未经确认的数据大小。

cwnd同rwnd相比不同的是:它只是发送方的一个内部参数,无需通知给接收方,其初始值往往比较小,然后随着数据包被接收方确认,窗口成倍扩大。

随着慢启动的cwnd窗口的不断增加,整个值会不断增大,可能会大于网络能处理的能力,造成网络的过载,表现就是数据丢包。而这个问题一旦出现,则cwnd会迅速衰减。

网络中实际传输的未经确认的数据大小取决于「rwnd」和「cwnd」中的小值。

拥塞避免

这里还有一个慢启动阈值「ssthresh」的概念,如果「cwnd」小于「ssthresh」,那么表示在慢启动阶段;如果「cwnd」大于「ssthresh」,那么表示在拥塞避免阶段,此时「cwnd」不再像慢启动阶段那样呈指数级增长,而是趋向于线性增长,以期避免网络拥塞,此阶段有多种算法实现。

调整「rwnd」到一个合理值

「rwnd」的合理值取决于BDP的大小,也就是带宽和延迟的乘积。假设带宽是 100Mbps,延迟是 100ms,那么计算过程如下:

BDP = 100Mbps * 100ms = (100 / 8) * (100 / 1000) = 1.25MB

为了最大限度的提升吞吐量,rwnd的大小最好是大于1.25MB的,Linux中通过配置内核参数里接收缓冲的大小,进而可以控制接收窗口的大小:

shell> sysctl -a | grep mem
net.ipv4.tcp_rmem = <MIN> <DEFAULT> <MAX>

调整「cwnd」到一个合理值

一般来说「cwnd」的初始值取决于MSS的大小,计算方法如下:

min(4 * MSS, max(2 * MSS, 4380))

以太网标准的MSS大小通常是1460,所以「cwnd」的初始值是3MSS。

当我们浏览视频或者下载软件的时候,「cwnd」初始值的影响并不明显,这是因为传输的数据量比较大,时间比较长,相比之下,即便慢启动阶段「cwnd」初始值比较小,也会在相对很短的时间内加速到满窗口,基本上可以忽略不计。

不过当我们浏览网页的时候,情况就不一样了,这是因为传输的数据量比较小,时间比较短,相比之下,如果慢启动阶段「cwnd」初始值比较小,那么很可能还没来得及加速到满窗口,通讯就结束了。

示例:

假设网页20KB,MSS大小1460B,如此说来整个网页就是15MSS。

如果cwnd的初始值为4MSS,则会经历如下:

如果cwnd的初始值为15MSS,则会经历:

那么是不是CWND值越大越好?首先,这个是否定的,因为实际传输的未经确认的数据大小取决于rwnd和cwnd中的最小值。

google的建议是10MSS。

如何查看初始cwnd?

通过握手阶段确认RTT为168,开始传输后得到第一个数据包的时间是409,加上RTT后就是577,从409到577之间有两个数据包,所以「cwnd」初始值是2MSS。

TLS优化 —— session reuse

  • Session Id:是在TLS握手过程中生成的。服务端可以将session id存起来,并同时存储id对应的具体信息。浏览器同时保存住这个id,在后续的ClientInfo阶段带上这个id,服务端根据这个id查询匹配的信息,从而快速的完成握手操作。
    • 缺点:
      1. 服务端需要存储,同时还需要检索详细信息
      2. 服务端不好控制id的失效时间
      3. 无法做到负载均衡,多机之间没有同步Session信息的话,如果客户端两次请求没有落在同一台机器上就无法找到匹配的信息
    • 优势:
      1. 客户端存储的数据比较小,请求时带上去的数据也小
  • Session Ticket:即会话记录单,即上面通过id要查询的详细信息。这个只需要存储在客户端即可,在ClientInfo阶段带上,直接给到服务端。
    • 缺点:
      1. 客户端存储的数据比较大,请求时带上去的数据也大
    • 优势:
      1. 服务端不需要存储,可以更好的控制过期时间,同时可以做负载均衡

通过 Wireshark 可以看到服务端发送 Ticket 的过程: 而session reuse被使用的情况,效果如下:

注意:IOS不支持session ticket

TLS优化 —— false start

TLS False Start 是指客户端在发送 Change Cipher Spec Finished 同时发送应用数据(如 HTTP 请求),服务端在 TLS 握手完成时直接返回应用数据(如 HTTP 响应)。

False Start 相当于客户端提前发送加密后的应用数据,不需要修改 TLS 协议,目前大部分浏览器默认都会启用。

TLS优化 —— OCSP Stapling

证书链

TLS 的身份认证是通过证书信任链完成的,浏览器从站点证书开始递归校验父证书,直至出现信任的根证书。站点证书是在 TLS 握手阶段,由服务端发送的。

证书应该尽可能的小,理想的证书应该是小于3kb的。

ECC Certificate

ECC能进一步减小证书的大小,具体的对比如下: 但是ECC在目前并没有得到很好的支持,XP系统不支持,android只有在4.0+的系统支持。

证书过期

前面说了,有时需要查询证书的状态,即OCSP(Online Certificate Status Protocol)。

OCSP 的问题在于,某些客户端会在 TLS 握手阶段进一步协商时,实时查询 OCSP 接口,并在获得结果前阻塞后续流程,这对性能影响很大。

而OCSP Stampling是对上面问题的优化措施,是指在证书中包含颁发机构对证书的OCSP查询结果,从而让浏览器跳过自己去验证的过程。服务端有更快的网络,获取 OCSP 响应更容易,也可以将 OCSP 响应缓存起来。

用wireshark看下网络的交互,可以看到服务端在发送完证书后,紧接着又发来了它的 OCSP 响应:

OCSP Stampling减少了3个RTT,如图:

tips: 由于OCSP会有缓存,所以优化不是马上有效果,并且只是偶然时刻的优化,所以这个优化提升不是很明显。

TLS优化 —— dynamic record size

动态块大小调整。

这个的优化是由于TLS协议层面的对头阻塞(head of line blocking)问题。即如果record数据不能有任何缺失,即使缺失1B,整个record都不能处理,后续的record也是无法处理的。

解决的方法是,类似于TCP的慢启动,可以在TLS 连接刚刚建立的时候,由于不知道网络状况以及拥塞情况,将 record 设置缩小,比如变成 1K, 在发送速度提升之后,再将 record size 设置为 16K(TLS一个记录块最大不能超过 16K)。

TLS优化 —— TLS1.3

0RTT Handshake,目前还在草稿阶段。

results matching ""

    No results matching ""