Skip to main content

16 HTTP的连接管理

短连接

短连接(short-lived connections):HTTP 协议最初(0.9/1.0)的通信过程采用了简单的请求 - 应答方式。底层的数据传输基于 TCP/IP,每次发送请求前需要先与服务器建立连接,收到响应报文后会立即关闭连接。

建立和断开连接占用大量时间,传输效率低。

长连接

长连接也叫持久连接(persistent connections):把建立和断开连接的时间成本由原来的一个请求 - 应答均摊到多个请求 - 应答上。

连接相关的头字段

HTTP/1.1 的连接默认启用长连接。向服务器发送了第一次请求,后续的请求都会重复利用第一次打开的 TCP 连接,在这个连接上收发数据。

可以在请求头里通过 Connection:keep-alive 明确地要求使用长连接机制 。如果服务器支持长连接,不管客户端是否明确要求,响应报文里都会放一个 Connection: keep-alive 表示后续请求复用当前连接。

TCP 连接长时间不关闭,服务器必须在内存里保存它的状态,占用服务器的资源。如果有大量的空闲长连接只连不发,会很快耗尽服务器的资源,导致服务器无法为真正有需要的用户提供服务。可以在请求头里加上 Connection: close 字段,告诉服务器这次通信后就关闭连接。服务器看到这个字段,明白客户端要主动关闭连接,在响应报文里也加上这个字段,发送之后就调用 Socket API 关闭 TCP 连接。

服务器端(Nginx)优化策略:

  • 使用 keepalive_timeout 指令,设置长连接的超时时间,如果在一段时间内连接上没有任何数据收发就主动断开连接,避免空闲连接占用系统资源。
  • 使用 keepalive_requests 指令,设置长连接上可发送的最大请求次数。比如设置成 1000,那么当 Nginx 在这个连接上处理了 1000 个请求后,也会主动断开连接。

队头阻塞

队头阻塞(Head-of-line blocking):是由 HTTP 基本的请求 - 应答模型所导致的。HTTP 规定报文必须是一发一收,这就形成了一个先进先出的串行队列。队列里的请求没有轻重缓急的优先级,只有入队的先后顺序,排在最前面的请求被最优先处理。如果队首的请求因为处理的太慢耽误了时间,那么队列里后面的所有请求也不得不跟着一起等待,结果就是其他的请求承担了不应有的时间成本。

性能优化

  • 并发连接(concurrent connections):同时对一个域名发起多个长连接,用数量来解决质量的问题。
  • 域名分片(domain sharding):多开几个域名,都指向同一台服务器,实际长连接的数量增加,用数量来解决质量的思路。