http/2 学习
自己对于http/2 的理解还停留在面试死记硬背的水平,所以最近对自己心中一些疑问以及自己的理解做一个总结,这些总结可能会有错误。如果有大佬觉得哪里有什么问题,可以直接说出。
http/2 的完整介绍很多。珠玉在前:http/2 简介 ,就不在赘述了。
问题一: http/2 为什么要使用二进制分帧层
二进制协议的理解:
对于这个问题,我们首先就要搞清楚什么http1.1的文本协议和htt/p2的二进制协议的不同了。其实我作为一个基础并不牢固的搬砖工,当看到这个二进制的时候我就在想:在计算机世界当中所有的内容不都是二进制吗?为什么还要有二进制以及文本协议之分呢?
带着这个问题,我在网上找到了一些回复,就直接搬下来吧
Binary protocol versus text protocol isn't really about how binary blobs are encoded. The difference is really whether the protocol is oriented around data structures or around text strings. Let me give an example: HTTP. HTTP is a text protocol, even though when it sends a jpeg image, it just sends the raw bytes, not a text encoding of them.
四级低空略过水平的翻译:
二进制协议和文本协议的区别并不是关于二进制blob是如何编码的。关键在于协议是以数据结构为导向还是以文本字符串为导向。
文本协议请求:其中所有的内容都是文字
[图片上传失败...(image-8fb482-1614501899169)]
二进制请求:
struct request {
int requestType;
int protocolVersion;
char path[1024];
char user_agent[1024];
char host[1024];
long int accept_bitmask;
long int language_bitmask;
long int charset_bitmask;
};
当我们看到http文本协议以及二进制请求的结构之后:
- 二进制协议比文本协议更加紧凑。
- 文本协议解析是需要特殊字符的,比如\r\n,一方面造成了文本协议更加冗长,另一方面使用这种特殊字符解析一段文字的方式,没有二进制解析方便快捷。
- 二进制协议中的数字比文本中的数字占用空间更小:比如http中状态码200,在文本协议中是 "2" "0" "0",这三个数字要分别用编码表示的,但是在二进制协议中,不用将数字编码成文本格式,直接用二进制表示数字就可以了: 11001000 。
http/2中的二进制分帧层
At the core of all performance enhancements of HTTP/2 is the new binary framing layer, which dictates how the HTTP messages are encapsulated and transferred between the client and server.
_
在许多文章中,都说http/2中的二进制分帧层,是http/2性能提升的关键,它给一个tcp链接同时发送多个请求提供了可能。
HTTP/1.1和HTTP/2都是基于TCP的协议,TCP模型是双向数据流,任何在一个TCP连接上处理超过一个请求的协议都需要解决这样两个问题:
- 分片——如何将流中的多个请求和响应拆分成独立的消息
- 对应——如何将请求和响应对应起来
在这两个问题中,我觉得第二个往往会让人忽略,就是在http1.1 中,一个tcp请求只能同时完成一个请求响应过程,所以请求以及响应天生一一对应,不存在响应和请求无法匹配的问题。但是当我们打开抓包工具查看相应的相关http报文的时候,会发现其实响应是没有一个字段去和请求一一对应的。这就给http/2的多路复用带来了问题,一个tcp连接中多个请求,多个响应,那么如何将这些响应和请求一一对应呢?只能在二进制分帧层添加字段了,所以在http/2帧的报文格式中,有一个字段是Stream Identifier,这个流ID可以将响应和请求一一对应。这个根本解决了多路复用,请求以及响应匹配的问题。
所以给这个问题来一个总结吧:
- 二进制协议比文本协议更加紧凑,减少占用空间。
- 分帧层相当于将http切分,更加灵活,比如可以对header帧做单独的特殊处理。
- 分帧层有着属于自己的报文头,其中的Stream Identifier 使得操作系统具备将多个响应以及请求一一匹配的能力,这个是http/2 性能提升的关键,也就是多路复用。
- 二进制分帧层存在的意义是将请求或响应切分,可以更加灵活处理。分帧层定义的报文格式,例如Stream Identifier等,直接关乎http/2 的各种优化方案的实现。
问题二:tcp与http/2的帧的关系
在http/2中帧是最小通信单位,我的问题是http/2 中的帧和最小的tcp数据包是什么关系,一一对应的吗?在http/2 的请求中,tcp是如何拆分以及组装消息的?
其中的解释如下:
- 同域名下所有通信都在单个连接上完成,消除了因多个 TCP 连接而带来的延时和内存消耗。
- 单个连接上可以并行交错的请求和响应,之间互不干扰
下面的解释当中,并行交错的请求和响应。其实这个并行请求应该具体为并行http请求,那么tcp可以将请求拆分并行请求吗?
TCP 数据包在 IP 数据包的负载里面。它的头信息最少也需要20字节,因此 TCP 数据包的最大负载是 1480 - 20 = 1460 字节。由于 IP 和 TCP 协议往往有额外的头信息,所以 TCP 负载实际为1400字节左右。因此,一条1500字节的信息需要两个 TCP 数据包
我们假设有两个post请求并行进行请求:
如果TCP协议层面并行请求,并将顺序打乱,这样可以吗?
在我看来其实这是不可以的,因为tcp协议是完全按照顺序组装数据包的,如果并行请求并将数据包顺序打乱,那么计算机将不知道如何组装这些数据包。
所以上面的并行请求是不准确的,在计算机内部一定是串行请求,发完一个请求的数据包,在发送下一个请求的数据包,这样才能保证数据包组合正确。
所以http/2中的帧,是按照顺序串行请求的,如果不是这样,数据将无从组装,一一对应。
总结一下吧:
- http/2中的帧是最小通信单位,但这仅仅是在http/2这一协议层。一个http/2中的帧,如果信息过多,可能是由多个tcp拆分组成,所以http/2中的帧概念,并不是一一对应网络协议中的一个数据包。
- 一个或多个tcp报文组成一个帧,一个或多个帧组成一个http/2的请求或者响应。
- http/2 一个tcp链接不存在并行传输,是串行传输,发送完一个帧的数据包,再发送下一个帧的相关数据包。
如果有哪些地方理解不到位,请不吝赐教