Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP2.0、HTTP3.0 #26

Open
Genluo opened this issue Aug 31, 2019 · 0 comments
Open

HTTP2.0、HTTP3.0 #26

Genluo opened this issue Aug 31, 2019 · 0 comments

Comments

@Genluo
Copy link
Owner

Genluo commented Aug 31, 2019

Http 1.1存在的问题

Http2.0出来的是解决Http1.1的问题,Http1.1存在什么问题?

  • 线头阻塞:TCP连接只能发送一个请求,前面的请求未完成之前,后续的请求都在排队
  • 多个HTTP/1.1可以支持并发请求,但是浏览器却很难实现,chrome和firefox等都禁用了并发,所以1.1版本请求并发依赖于多个TCP连接,建立TCP连接成本很高,还会存在慢启动等问题
  • 头部冗余,采用文本格式,首部没有被压缩,而且每一个请求上带上cookie、user-agent等完全相同的首部
  • 客户端都主动请求,服务器不能主动推动

Http2.0重大改进

二进制分帧层

Http2.0性能提升的核心就在于二进制分帧层,HTTP2是二进制协议,他采用二进制格式传输数据而不是1.x 的文本格式

http1.1响应的是文本格式,而http2.0把响应划分为两个帧,图中的Headers(首部)和DATA(消息负载)是帧的类型,也就是说一条HTTP响应,划分成两个帧来传输,并且采用二进制来进行编码

  • 流(stream):已建立的TCP连接的双向字节流,可以承载一个或多个消息
  • 消息(Message):一个完整的HTTP请求或者响应,由一个或者多个帧组成,特定消息的帧在同一个流上发送,这意味着一个HTTP请求或者响应只能在一个流上发送
  • 帧(Frame):通信的基本单位,一个TCP上可以有着任意数量的流

多路复用

Http1.1中出现的线头阻塞和多个TCP连接的问题,Http2.0多路复用完美解决,让Http2.0所有的通信都在一个TCP连接上完成,真正实现了请求的并发

HTTP2建立一个TCP连接,一个连接上面可以有任意多个流(stream),消息分割成一个或者多个帧在流里面传输,帧传输过去以后,在进行重组,形成一个完成的请求或者响应,这使得所有的请求或者响应都无法阻塞。

头部压缩

头部压缩也是HTTP2的一大亮点,在1.x的版本中,首部使用文本格式传输,通常会给每个传输增加500-800字节的开销,我们发现现在打开一个网页上百个请求都是常态,而每个请求带的一些首部字段都是相同的,例如cookie、user-agent等,HTTP2为此采用HPACK压缩格式来压缩头部,头部压缩需要在浏览器和服务器之间:

  • 维护一份相同的静态字典,包含常见的头部名称,以及常见的头部名称和值的组合
  • 维护一份相同的动态字典,可以动态的添加内容,
  • 通过静态Huffman编码对传输的首部字段进行编码

所以我们在传输首部字段的时候,例如传输method:Get那么我们只需要传输静态字典中对应的索引就可以了,一个字节搞定,像user-agent、cookie这种静态字典里面的只有首部而没有值的首部,第一次传输需要user-agent在静态字典中索引以及他的值,值会采用静态Huffman编码来减小体积,第一次传输过user-agent之后,浏览器和服务器就会把他添加到自己的动态字典中,后续传输就可以传输索引了,一个字节搞定

服务器端推送

服务器端推送使得服务器可以预测客户端需要的资源,主动推送到客户端,例如:当客户端请求index.html,服务器能够额外推送script和style,实现的原理就是客户端发出页面请求的时候,服务器端能够分析这个页面所依赖的其他资源,主动推送到客户端的缓存,当客户端收到原始网页的请求,他需要的资源已经位于缓存中。

针对每一个希望发送的资源,服务器会发送一个PUSH_PROMISE帧,客户端可以通过发送RES_STREAM帧来拒绝推送(当资源已经位于缓存)。这一步操作先于父响应,客户端了解到服务器端打算推动那些资源,就不会为这些资源创建重复请求。当客户端收到index.html的响应是,相应的资源已经位于缓存中。

多路复用和keep alive的区别

通过上面这张图可以看出,长连接可以解决复用TCP连接的功能,但是还是无法解决请求阻塞问题,也就是一个请求的开始需要在等上一个请求结束才可以发起,为什么会存在这个问题,因为Http1.1是通过需要每条请求都是可识别的,按照顺序发送,否则server就不能判断相应的是哪个具体的请求。那么Http2.0中是这样解决这个问题的,在同一个域名下,开启一个TCP的connection连接,每个请求以stream的方式进行传输,每个stream有唯一的标识,connection一旦建立,后续的请求都可以复用这connection并可可以同时发送,server端可以根据stream的唯一标识对应的请求。

多路复用什么时候关闭

多路复用根据标准显示,会在下面两个时机关闭:

  • 用户离开这个页面
  • server主动关闭这个connection

但是标准是这样,每个服务器都有自己的实现

参考的资料

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant