HTTP请求并发与TCP连接的爱恨情仇

1,001 阅读8分钟

背景

领导要优化性能,指着 Performance 报告说:小B,快去看看,这些请求为什么头和尾巴那么长,我们是技术部门,任何一点优化都不能放过,懂?
小B:....我懂你个大头鬼

Chrome网络请求耗时分析

network工具能看到http请求耗时,我先贴一个官方解释,这年头官方最靠谱:

-   **Queueing**. The browser queues requests when:
    -   There are higher priority requests.
    -   There are already six TCP connections open for this origin, which is the limit. Applies to HTTP/1.0 and HTTP/1.1 only.
    -   The browser is briefly allocating space in the disk cache

-   **Stalled**. The request could be stalled for any of the reasons described in **Queueing**.

-   **DNS Lookup**. The browser is resolving the request's IP address.

-   **Initial connection**. The browser is establishing a connection, including TCP handshakes/retries and negotiating an SSL.

-   **Proxy negotiation**. The browser is negotiating the request with a [proxy server](https://en.wikipedia.org/wiki/Proxy_server).

-   **Request sent**. The request is being sent.

-   **ServiceWorker Preparation**. The browser is starting up the service worker.

-   **Request to ServiceWorker**. The request is being sent to the service worker.

-   **Waiting (TTFB)** . The browser is waiting for the first byte of a response. TTFB stands for Time To First Byte. This timing includes 1 round trip of latency and the time the server took to prepare the response.

-   **Content Download**. The browser is receiving the response, either directly from the network or from a service worker. This value is the total amount of time spent reading the response body. Larger than expected values could indicate a slow network, or that the browser is busy performing other work which delays the response from being read.

下面是我的理解:

  • Queueing:
    请求排队时间,在这段时间,浏览器并没有接收到要发送这个请求的命令。有三种情况可能排队:
    1. 有优先级更高的请求需要发送,优先级则根据文件类型进行区分。通常,html,js,css为主要文件,该种类型文件等候时间较短;而其他类型,如jpg,png或者媒体文件,字体文件等则等候时间较长,等待时间长度较长时,将会导致文件加载缓慢,也就是常说的加载时挂起;
    2. 同域名下当前有6个TCP连接了,需要等待其中某个请求结束释放TCP连接,才能轮到本请求
    3. 生成磁盘缓存条目所用的时间(通常非常迅速)。但实际情况看,
  • Stalled:浏览器得到要发出请求的指令后,到请求可以发出的等待时间,Chrome自己说上述能造成 Queueing 的原因都可能引起 Stalled
  • DNS Lookup:DNS解析时间,如果解析过就会在本地缓存下来,后面同个域名就很快
  • Initial connection:建立TCP连接(握手)和SSL时间
  • Proxy negotiation:浏览器与代理协商的时间
  • Request sent:请求第一个字节发出前到最后一个字节发出后时间
  • Waiting(TTFB,Time to First Byte):请求发出后,到收到响应的第一个字节所花费的时间
  • Content Download:收到响应的第一个字节,到接收完最后一个字节的时间,就是下载时间。可以是从网络返回的,也可以是从Service Worker返回的。如果比预期时间长,原因可能是网络太慢(下载数据慢)或者浏览器忙于其他工作而没开始读返回

其他的都很清楚,就 Stalled不太清楚,后来又看到一段Stalled的解释,文章在后面会贴出来,大概结论是:

1,单一服务发送时候stalled过长,往往是丢包所致,这也意味着网络或服务端有问题。  
2,多个服务并发导致stalled过长,是浏览器对同一个主机域名的并发连接数有限制,过长的请求是被阻塞了,处在队列中等待tcp连接

分析

打开F12,随便找个请求,可以看到耗费时长如下:

image.png 我们这里看出,Queueing -> initial connection -> Request sent -> Waiting -> Content Download 是串行的,这从概念上也很好理解。ssl耗时属于initial connection的一部分。问题是,这里还有个Stalled,它是串行的吗?我们加一下时间,发现在这里,它的耗时是单独计算的,总耗时 = Stalled + 前面的提到的其他耗时

但真的是这样?我们看下一张图

image.png

一眼看出,Stalled 和Initial connection 耗时是会重叠的,这里我其实非常不明白!Stalled阶段不是还没发请求吗?为什么Initial connection又开始Tcp连接了呢?stalled到底是什么原因造成的?谁来救救我!!!

TCP复用

上文提到了,Chrome浏览器同域名下最多有6个TCP连接,请求超过这个数就要等待,这又是什么呢?我们先简单了解下 HTTP 协议

HTTP/1.0

与本文无关的省略,只需知道,HTTP 这个应用层协议是以 TCP 为基础来传输数据的。当你想访问一个资源时,需要先解析这个资源的 IP 地址和端口号,从而和这个 IP 和端口号所在的服务器建立 TCP 连接(三次握手),然后 HTTP 客户端发起服务请求报文,服务器对服务器的请求报文做出响应,客户端收到所有响应后就会关闭 TCP 连接(四次挥手)

在 HTTP/1.0 协议下,每次 HTTP 请求都会建立 TCP 连接,等这次请求结束后, TCP 连接就会关闭,后续请求就会一直重复 TCP 连接/关闭动作

HTTP/1.1

HTTP 1.1 允许 HTTP 在执行完一次事务之后将连接保持在打开状态,也就是不断开 TCP 连接,以便于下一次的 HTTP 事务能够复用这条连接。

在一次 HTTP 事务结束之后仍旧保持打开状态的 TCP 连接被称为持久连接。

持久连接

持久连接通常可以称为 Keep-Alive。

在 HTTP/1.0 中其实也可以开启持久连接,这就需要在请求头中加入字段:

Connection: Keep-Alive

当服务端收到请求时,返回请求加上同样header

Connection: Keep-Alive

在 HTTP/1.1 中,持久连接是默认开启的。如果需要关闭 Keep-Alive,则请求添加如下头:

Connection: close

如果 TCP 连接一直开着,但后面又没 HTTP 请求了,不就造成资源浪费了?尤其是服务端需要对接那么多客户端?

答案是为了避免资源浪费的情况,服务端一般会设置 keep-alive的超时时间。比如设置了 HTTP 长连接的超时时间是 60 秒,服务端就会启动一个定时器,如果客户端在完后一个 HTTP 请求后,在 60 秒内都没有再发起新的请求,定时器的时间一到,就会触发回调函数来释放该连接。

TCP 的Keep-Alive:上面说的是持久连接,也就是 HTTP 的keep-alive,但有一种说法是 TCP的keep-alive,其实也就是 TCP 保活机制。在一定时间段里如果没有收到请求,那么保活机制会建个的发送探测报文,如果都没得到相应,那这个 TCP 可能就出现问题了,就会通知到上层应用

常见问题

  1. 网页中的图片资源为什么分放在不同的域名下?

我们已经知道,浏览器对并发请求的数目限制是针对域名的(也就是 TCP 连接个数),即针对同一域名(包括二级域名)在同一时间支持的并发请求数量的限制。如果请求数目超出限制,则会阻塞。因此,网站中对一些静态资源,使用不同的一级域名,可以提升浏览器并行请求的数目,加速界面资源的获取速度。

  1. 浏览器与服务器建立一个TCP连接后,是否会在完成一个http请求后断开?什么条件下会断开?

HTTP/1.0 中,该请求结束后就断开,HTTP/1.1 将Connection写入了标准,默认值为keep-alive。除非强制设置为Connection: close,才会在请求后断开TCP连接。

  1. 一个TCP连接可以同时发送几个HTTP请求?

HTTP/1.1 中,单个TCP连接,在同一时间只能处理一个 HTTP 请求,虽然存在Pipelining技术支持多个请求同时发送,但由于实践中存在很多问题无法解决,所以浏览器默认是关闭,所以可以认为一个 TCP 在某一时间只能发一个 HTTP 请求
HTTP2 提供了多路传输功能,多个http请求,可以同时在同一个TCP连接中进行传输

  1. 浏览器 HTTP 请求的并发性是如何体现的?

浏览器会同时和服务器建立多个 TCP 连接,在同一个TCP连接上顺序处理多个 HTTP 请求。所以浏览器的并发性就体现在可以建立多个TCP连接上。
Chrome浏览器最多允许对同一个域名Host建立6个TCP连接,不同的浏览器有所区别

  1. 为什么要限制 TCP 连接个数?不应该越多越快吗?

需考虑浏览器和服务器压力,以及恶意攻击(Dos)的可能性

  1. 为什么有的时候刷新页面不需要重新建立 SSL 连接?

TCP 连接有的时候会被浏览器和服务端维持一段时间。TCP 不需要重新建立,SSL 自然也会用之前的

参考

Stalled 耗时过长问题抓包

一篇还没来得及看的图文