说说http的持久链接

269 阅读3分钟

什么是http的持久链接?

说起http在大家心中的印象就是建立TCP链接,发起请求,服务器响应完成后断开链接,如果还有其他请求就再次建立TCP链接,即所谓的短链接。我们知道每次建立TCP链接是需要三次握手的,成本会很高,那这样http性能会很差,有没有优化空间呢?当然有,就是我们今天要说的http的持久链接(persistent connection),服务器与客户端建立链接后,并不会立即断开,在这个链接上客户端可以多次请求,我们减少了TCP的创建,因此也减少了服务器创建TCP带来的开销。

http1.0的持久链接

其实早在http1.0时,就已经支持持久链接了,客户端请求时,只需要在header中声明如下

Connection: keep-alive

仅仅客户端支持还是远远不够的,服务器也是需要支持的,当同时满足条件时,才会保持持久链接,虽然持久链接在1.0时代就已经实现,但是它并不是没有缺点的,我们在同一个TCP链接下,发出多个请求,这些请求会按照时间顺序依次处理,在第一个请求没有处理完成时,是不会发出第二个请求的,这虽然减少了服务器的开销,但是对于客户端来说,实在是太慢了,万一第一个请求超时,之后的请求必然受到影响,这就是线头阻塞(Head-of-Link Blocking);

http1.1对持久链接的优化

http1.1对持久链接有了更好的支持

  • 默认开启了持久链接
  • 管道技术(HTTP Pipelining)

由于在http1.0持久链接中,下一个请求必须等待上一个请求完成后才可执行,所以在http1.1中引进了管道技术,它可以一次发送多个请求,而不用等待上一个请求,但是响应的顺序还是按照请求时的的顺序来的。

http1.0 无管道技术

sequenceDiagram
客户端->>服务器: request1
服务器->>客户端: respone1
客户端->>服务器: request2
服务器->>客户端: respone2

http1.1 管道技术(HTTP Pipelining)

sequenceDiagram
客户端->>服务器: request1
客户端->>服务器: request2
客户端->>服务器: request3
服务器->>客户端: respone1
服务器->>客户端: respone2
服务器->>客户端: respone3

管道技术虽然不用等待响应,提高了性能,但是还是没有解决掉线头阻塞的问题。

http2

在http2时代,线头阻塞问题终于被解决了,那就是多路复用 (Multiplexing) 为了实现多路复用,http2引入了二进制数据帧的概念,它将数据封装成帧,每一帧都有顺序标识,并行发送数据,拿到数据后会按照标识合并成原来的数据,这样实现了并行发送,解决了线头阻塞的问题。

http2 多路复用 (Multiplexing)

sequenceDiagram
客户端->>服务器: request1
客户端->>服务器: request2
客户端->>服务器: request3
客户端->>服务器: request4
服务器->>客户端: respone4
服务器->>客户端: respone1
服务器->>客户端: respone3
服务器->>客户端: respone2

keepalive 配置

虽说http1.1已经默认开启持久链接了,但是并不一定就会发挥效果,还是需要客户端与服务器配合使用,在客户端与服务器都开启持久链接的情况下,如果有用到nginx之类的web服务器,还是要配置的,不然没有效果,一般nginx.conf默认配置如下

keepalive_timeout  65;

不启用则可以设置keepalive_timeout为0

当想要知道服务器有没有开启持久链接时,可以查看请求头,Connection: keep-alive就表示服务器已经开启,客户端如果想要关闭持久链接,在最后一次请求中设置header头如下

Connection: close

总结

  1. http 1.0 中默认启用Keep-Alive需要声明
  2. http 1.1 中默认启用Keep-Alive,如果加入”Connection: close ”,才会关闭持久链接
  3. http2实现了多路复用,解决了线头阻塞

开启持久链接优点

  • 服务器减少TCP创建带来的开销
  • 客户端不用频繁创建TCP节约了时间

开启持久链接缺点

  • 使用不当会造成TCP不能及时释放,浪费服务器资源
  • http1.0和1.1会带来线头阻塞问题