HTTP3.0(QUIC的实现机制)

回顾HTTP2.0

HTTP1.1在应用层以纯文本的形式进行通讯,每次通讯都要带完整的HTTP的头,并且不考虑pipeli模式的化,每次的过程老是像上面描述的那样一去一回。那样在实时性、并发想上都存在问题css

头部压缩:HTTP2.0会对HTTP的头进行必定的压缩,将原来每次都要携带的大量key value在两端创建一个索引表,对相同的头只发送索引表中的索引算法

HTTP2.0协议将一个TCP的链接中,切分红多个流。每一个流都有本身的ID,并且流能够是客户端发服务端,也能够是服务端发客户端,它其实只是一个虚拟的通道。流是有优先级的缓存

HTTP2.0还将全部的传输信息分割为更小的信息和帧,并对它们采用二进制格式编码。常见的帧有Header帧,用于传输Header内容,而且会开启一个新的流,再就是Data帧,用来传输正文实体。多个Data帧属于一个流服务器

经过这两种机制,http2.0的客户端能够将对个请求不一样的流中,而后将请求内容拆成帧,进行二进制传输。这些真能够打散乱序发送,而后根据每一个帧首部的流标识符从新组装,而且能够根据优先级,决定先处理那个流的数据并发

二进制传输就是以上tcp

例子:性能

假设一个页面要发送三个独立的请求,一个获取css,一个获取js,一个获取图片jpg。若是使用HTTP1.1就是串行的,可是若是使用HTTP2.0,就能够在一个链接里,客户端和服务端均可以同时发送多个请求或回应,并且不用按照顺序一对一对应
image
http2.0成功解决了http1.1的队首阻塞问题,同时,也不须要经过http1.x的pipeline机制用多条tcp链接来实现并行请求和响应;减小了tcp链接数对服务器性能的影响,同时将页面的多个数据css,js,jpg等经过一个数据连接进行传输,可以加快页面组件的传输速度。ui

QUIC协议

HTTP2.0 也是基于TCP协议的,tcp协议在处理包时是有严格顺序的google

当其中一个数据包遇到问题,TCP链接须要等待找个包完成重传以后才能继续进行,虽然HTTP2.0经过多个stream,使得逻辑上一个tcp链接上的并行内容,进行多路数据的传输,然而这中间没有关联的数据,一前一后,前面stream2的帧没有收到,后面stream1的帧也会所以堵塞编码

因而google的 QUIC协议从TCP切换到UDP

  • 机制一:自定义链接机制
    一条tcp链接是由四元组标识的,分别是源ip、源端口、目的端口,一旦一个元素发生变化时,就会断开重连,从新链接。在次进行三次握手,致使必定的延时

在TCP是没有办法的,可是基于UDP,就能够在QUIC本身的逻辑里面维护链接的机制,再也不以四元组标识,而是以一个64
位的随机数做为ID来标识,并且UDP是无链接的,因此当ip或者端口变化的时候,只要ID不变,就不须要从新创建链接

  • 机制二:自定义重传机制
    tcp为了保证可靠性,经过使用序号和应答机制,来解决顺序问题和丢包问题

任何一个序号的包发过去,都要在必定的时间内获得应答,不然一旦超时,就会重发这个序号的包,经过自适应重传算法(经过采样往返时间RTT不断调整)

可是,在TCP里面超时的采样存在不许确的问题。例如发送一个包,序号100,发现没有返回,因而在发送一个100,过一阵返回ACK101.客户端收到了,可是往返的时间是多少,无法计算。是ACK到达的时候减去第一仍是第二。

QUIC也有个序列号,是递增的,任何宇哥序列号的包只发送一次,下次就要加1,那样就计算能够准确了

可是有一个问题,就是怎么知道包100和包101发送的是一样的内容呢?quic定义了一个offset概念。QUIC既然是面向链接的,也就像TCP同样,是一个数据流,发送的数据在这个数据流里面有个偏移量offset,能够经过offset查看数据发送到了那里,这样只有这个offset的包没有来,就要重发。若是来了,按照offset拼接,仍是可以拼成一个流。

image

  • 机制三: 无阻塞的多路复用

有了自定义的链接和重传机制,就能够解决上面HTTP2.0的多路复用问题

同HTTP2.0同样,同一条 QUIC链接上能够建立多个stream,来发送多个HTTP请求,可是,QUIC是基于UDP的,一个链接上的多个stream之间没有依赖。这样,假如stream2丢了一个UDP包,后面跟着stream3的一个UDP包,虽然stream2的那个包须要从新传,可是stream3的包无需等待,就能够发给用户。

  • 机制四:自定义流量控制

TCP的流量控制是经过滑动窗口协议。QUIC的流量控制也是经过window_update,来告诉对端它能够接受的字节数。可是QUIC的窗口是适应本身的多路复用机制的,不但在一个链接上控制窗口,还在一个链接中的每一个steam控制窗口。

在TCP协议中,接收端的窗口的起始点是下一个要接收而且ACK的包,即使后来的包都到了,放在缓存里面,窗口也不能右移,由于TCP的ACK机制是基于序列号的累计应答,一旦ACK了一个序列号,就说明前面的都到了,因此是要前面的没到,后面的到了也不能ACK,就会致使后面的到了,也有可能超时重传,浪费带宽

QUIC的ACK是基于offset的,每一个offset的包来了,进了缓存,就能够应答,应答后就不会重发,中间的空档会等待到来或者重发,而窗口的起始位置为当前收到的最大offset,从这个offset到当前的stream所能容纳的最大缓存,是真正的窗口的大小,显然,那样更加准确。
image