我们经常谈论 http2 与 http1.1,却经常忽视一些细节的区别。最近谈到 keep-alive 与 http2 链路复用的区别。虽然我知道 http2 的多路复用技术是源自通信工程里的时分复用,但对 keep-alive 的复用却有些模糊。下面看来这些技术之间的进化。
keep-alive
有很多文章都说 http2 相比 http1.1 增加了连接复用。这句话其实是不准确的。
在 HTTP 1.1 中 所有的连接默认都是持续连接,除非特殊声明不支持。 而在 http1.0 中,官方没有支持 keep-alive, 通常会手动在请求头中添加 Connection: Keep-Alive
。
keep-alive 就是 TCP 连接复用的开端。改善的效果就是不再重新建立TCP连接,省去 三次握手 的时间。如下图:
优势有:
- 较少的CPU和内存的使用(由于同时打开的连接的减少了)
- 允许请求和应答的HTTP管线化
- 降低拥塞控制 (TCP连接减少了)
- 减少了后续请求的延迟(无需再进行握手)
- 报告错误无需关闭TCP连接
http pipelining
有些文章中会有一个误区,就是TCP连接必须等一个请求响应完成后,才能复用。这是不对的,但其实可以注意上面优势里提到到 http pipelining
,如下图:
HTTP1.1 中,一个TCP连接里是可以同时发送(实际有先后,但可以在响应前)多个请求的。但它是有序的,遵循先进先出,服务端只能按顺序响应请求(如果前面的请求没有响应完成或需要很长时间,后面的请求就会被阻塞),所以可能发生 队头阻塞(HOL blocking),造成延迟。
连续的 GET 和 HEAD 请求总可以管线化的。一个连续的幂等请求,如 GET,HEAD,PUT,DELETE,是否可以被管线化取决于一连串请求是否依赖于其他的。
所以keep-alive 的劣势也很明显:
- Keep-Alive可能会极大的影响服务器性能,因为它在文件被请求之后还保持了不必要的连接很长时间
- 可能发生队头阻塞(HOL blocking),造成延迟
HTTP2
HTTP2 主要解决的问题也是 TCP连接复用。但它比 keep-alive 更彻底,类似于通信工程里的时分复用,多个请求可以同时发送(不分先后),同时响应,解决了 队头阻塞(HOL blocking)的问题,极大提高效率。
keep-alive 的 HTTP pipelining 相当于单线程的,而 HTTP2 相当于并发。
HTTP2 的优点:
- 对HTTP头字段进行数据压缩(即HPACK算法);
- HTTP/2 服务端推送(Server Push);
- 请求管线化;
- 修复HTTP/1.0版本以来未修复的 队头阻塞 问题;
- 对数据传输采用多路复用,让多个请求合并在同一 TCP 连接内。
后三个优点其实都是 多路复用 带来的优点。