概述
本文主要讨论从http1.x协议到http2.0协议的通信方式发展历程
连接的四种模式
一次请求一个tcp连接
每次都需要新建连接
连接池
对于底层连接的复用,降低第一种模式下建立tcp连接的时间开销。
之前的博客有分析过这种连接模式的源码 -- Golang Http RoundTrip解析_zhanglehes的专栏-CSDN博客
Pipelining
它是一项浏览器的技术,在1.1版本中提出了协议标准。其基本思想是当一个网页中包含多个对象是,使用pipelining技术可以一次把所有的请求推送到server端,然后等待server按照顺序返回每个请求的结果。
Pipelining协议提出先发出的请求,需要先返回的规定。这里包含了优先级的概念,个人理解也是和浏览器加载顺序有关的。但这个规则不管在浏览器上还是服务中后台使用上都可能存在性能问题。是想如果前面的请求非常耗时(比如它依赖的资源暂时获取不到),那么后面的请求需要等待前面请求处理完成后才能返回给客户端(head-of-line),这里还是考虑到server并行处理请求的情况。另外即使前面请求处理速度较快,但是若产生的结果大小较大,则需要花费大量时间在网络传输上,这时后面请求的结果也是无法及时传递的。结合上述两个例子,pipelining提出并行化所产生的性能优势在某些场景下就无法实现。
另外Pipelining技术还存在安全性的问题。
Pipelining协议在浏览器和服务端中后台的使用都并不广泛。通常会使用1与2两者结合的方式,也就是多个连接加长连接的方式,提升整体性能。虽然如此,但Pipelining协议仍然尤其重要的价值:1、它对底层连接的使用率更高;2、它颠覆了请求发送、等待服务端返回的传统模式,能并发的发送请求。个人认为http2上还是借鉴了不少Pipelining协议的思想,并对它不足之处进行了调整。
Multiplexing
这是http2使用的消息传输方式,后面有更详细的介绍。
http2与http1.x的不同
原有http协议中的methods, status codes, URIs, and header fields仍旧保持一致,只是底层client和server的交互方式发生了改变。通过在协议层中增加了binary framing层,引起交互方式的改变。也就是对于直接使用http库的应用方来说代码不需要更改,但是你的代码直接使用socket的话就需要考虑到http2所带来的变化了。
- 引入二进制桢作为基本的通信单元(Binary framing layer),Request和response会被拆分后进行发送,通过stream id来识别和组合请求;
- 一对client和server只使用一个tcp连接,所有请求复用该连接;
- 不同的Requests和responses的发送可以相互交迭,而不再保留原先的一来一回的通讯方式;
http2底层通信的基本概念
流(stream) – 一个双向传输的虚拟连接,可以发送和接收一条或多条消息。Client发送的stream id为单数,server发送的stream id为双数,以此避免冲突和匹配request、response对(待确认);
消息(message) – 等同于原先的request和response,可以由多个桢组成。一个流包含多个requests活着responses,可能是在原有通信框架的一种扩充,grpc支持streaming的方式就和这有关;
桢(frame) – 通信的最小单位,有不同的种类;
In short, HTTP/2 breaks down the HTTP protocol communication into an exchange of binary-encoded frames, which are then mapped to messages that belong to a particular stream, all of which are multiplexed within a single TCP connection. This is the foundation that enables all other features and performance optimizations provided by the HTTP/2 protocol.
关于使用同一个tcp连接发送requests和response,我理解有两层含义。一是之前长连接的方式,client在发送一个request后,会等待这个连接返回response,因此在等待的过程中这个连接其实是闲置的。而http2协议带来的改变是client在发送出request1后,可以使用同一个连接接着发送request2,而不必等待response1的返回。二是之前的传出模式,都需要发送完整的消息,这样一旦前面消息较大的话,后面的消息则需要排队。http2协议通过二进制桢的方式对此进行了颠覆,它把request拆分成了若干个包,不同的requests因此可以交叉发送,由server端再把这些包重新给组装起来。
参考文献
http2官方文档 -- Introduction to HTTP/2 | Web Fundamentals | Google Developers
二进制桢 -- HTTP/2协议之二进制桢【原理笔记】 - 云+社区 - 腾讯云
概述 -- 深入理解http2.0协议,看这篇就够了! - 知乎
http1 vs http2 -- HTTP/1.1 vs HTTP/2: What's the Difference? | DigitalOcean