HTTP学习笔记(四)
短链接
HTTP 协议最初(0.9/1.0)是个非常简单的协议,通信过程也采用了简单的“请求 - 应答”方式。
它底层的数据传输基于 TCP/IP,每次发送请求前需要先与服务器建立连接,收到响应报文后会立即关闭连接。
因为客户端与服务器的整个连接过程很短暂,不会与服务器保持长时间的连接状态,所以就被称为“短连接”(short-lived connections)。早期的 HTTP 协议也被称为是“无连接”的协议。
长连接
针对短连接暴露出的缺点,HTTP 协议就提出了“长连接”的通信方式,也叫“持久连接”(persistent connections)、“连接保活”(keep alive)、“连接复用”(connection reuse)。
其实解决办法也很简单,用的就是“成本均摊”的思路,既然 TCP 的连接和关闭非常耗时间,那么就把这个时间成本由原来的一个“请求 - 应答”均摊到多个“请求 - 应答”上。
长短连接对比:

相关头字段:
- Connection:(响应字段)想要长连,接取值keep-alive。由服务器告知客户端,服务器支持长连接。
- 在 HTTP/1.1 中的连接都会默认启用长连接。不需要用什么特殊的头字段指定,只要向服务器发送了第一次请求,后续的请求都会重复利用第一次打开的 TCP 连接,也就是长连接,在这个连接上收发数据。当然也可以 明确使用长连接。
缺点:
TCP 连接长时间不关闭,服务器必须在内存里保存它的状态,这就占用了服务器的资源。
如果有大量的空闲长连接只连不发,就会很快耗尽服务器的资源,导致服务器无法为真正有需要的用户提供服务。
所以,长连接也需要在恰当的时间关闭,不能永远保持与服务器的连接,这在客户端或者服务器都可以做到。
- Connection: (请求字段)close。客户端告知服务端,停止长连接。同时在客户端的响应字段也加上Connection: close,此时,长连接关闭。
服务器端通常不会主动关闭连接,但也可以使用一些策略。拿 Nginx 来举例,它有两种方式:
- 使用“keepalive_timeout”指令,设置长连接的超时时间,如果在一段时间内连接上没有任何数据收发就主动断开连接,避免空闲连接占用系统资源。
- 使用“keepalive_requests”指令,设置长连接上可发送的最大请求次数。比如设置成 1000,那么当 Nginx 在这个连接上处理了 1000 个请求后,也会主动断开连接。
- 另外,客户端和服务器都可以在报文里附加通用头字段“Keep-Alive: timeout=value”,限定长连接的超时时间。但这个字段的约束力并不强,通信的双方可能并不会遵守,所以不太常见。
队头阻塞
“队头阻塞”与短连接和长连接无关,而是由 HTTP 基本的“请求 - 应答”模型所导致的。
根源:HTTP是半双工的协议,只能一发一收,这是对头阻塞的本质。
因为 HTTP 规定报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列。队列里的请求没有轻重缓急的优先级,只有入队的先后顺序,排在最前面的请求被最优先处理。
如果队首的请求因为处理的太慢耽误了时间,那么队列里后面的所有请求也不得不跟着一起等待,结果就是其他的请求承担了不应有的时间成本。

性能优化
请求 - 应答”模型不能变,所以“队头阻塞”问题在 HTTP/1.1 里无法解决,只能缓解。
并发连接
就是同时对一个域名发起多个长连接,用数量来解决质量的问题。
但这种方式也存在缺陷。如果每个客户端都想自己快,建立很多个连接,用户数×并发数就会是个天文数字。服务器的资源根本就扛不住,或者被服务器认为是恶意攻击,反而会造成“拒绝服务”。
所以,HTTP 协议建议客户端使用并发,但不能“滥用”并发。RFC2616 里明确限制每个客户端最多并发 2 个连接。不过实践证明这个数字实在是太小了,众多浏览器都“无视”标准,把这个上限提高到了 6~8。后来修订的 RFC7230 也就“顺水推舟”,取消了这个“2”的限制。
域名分片
由于HTTP和浏览器的并发限制,该方法还是用数量来解决质量的思路,
即:建立多个域名到同一个ip的映射,而这些域名都指向同一台服务器,对于网络请求进一步分流,这样实际的长连接就上去了。
疑问:多开几个域名,最终都是指向一个服务器,那跟都直接连一个服务器的效果一样,对服务器的性能要求一样,没有减少后端的压力?
域名分片解决的是客户端并发的问题,可以创建更多的连接。 比如浏览器限制一个域名最多6个连接,域名分3片,那么浏览器就可以同时建立18个连接,显然就能够并发更多请求,获取数据也就快了。
其他知识补充:
- 服务端开发,长短连接如何选择?
- 一般使用长连接,除非明确知道只会发送一个请求,比如游戏内
- 连接兑换码服务进行礼包兑换。
- 并发请求和并发连接
- 并发请求:服务端的概念,有多个客户端连接服务器。
- 并发连接:客户端的概念,一个浏览器并发多个连接,访问服务器(有可能是一个用户)。