前段时间面试 遇到的这个问题 当时答得不好,现在做个复盘整理
Http1.1
首先介绍一下Http1.1
性能
长连接
1.0存在一个很大的性能问题就是,每次TCP都要三次握手,1.1就采用长连接的方式,减少重复建立连接带来的性能问题,长时间没有数据交互就会断开连接。
管道网络传输
简而言之,不用等回复,就可以直接发下一个请求,但是接受响应还是要延迟的,因为是根据请求的顺序返回响应的,所以解决了队头阻塞问题,但是没有解决响应的队头阻塞
优点
灵活易拓展 OSI第七层,底下的层可以随意拓展,比如TCP和UDP 比如在HTTP和TCP之间增加了TLS安全传输层
天然跨平台
缺点(缺点才是比较重要的,也就是后面升级的原因):
好处:不需要额外的资源去存储资源信息
坏处:每次操作都要鉴权(可以用Cookie解决)
Http1.0和1.1的区别
改进:
缺点:
Http2.0的优化
HTTP/2是基于HTTPS的,所以安全性有保障
优点
上面我们说到会有队头阻塞的问题?
ok,Http/2就很厉害了,引出了Stream的概念,多个Stream复用在一条TCP连接上。1个TCP包含多个Stream,一个Stream有多个Message,一个个Message包含多个Frame,就是上面压缩的东西
每一个Stream都有一个ID,这样就解决了上面的队头阻塞的问题了。
缺点
队头阻塞问题不在传输层了,在网络层,TCP接受数据按照Segment来接收,有的早到 有的迟到或者丢失 还要等重传,所以这个阻塞着。
Http3.0的优化
上面2.0的问题是TCP的问题,于是直接换成UDP了。是基于UDP的QUIC协议,这里就不展开了。
优点
3.多路复用:QUIC基于UDP,一个连接上的多个stream之间没有依赖,即使丢包,只需要重发丢失的包即可,不需要重传整个连接。
QUIC 如何保证可靠传输?
Packet Header:分为Long Packet Header用于首次建立连接、和Short Packet Header用于日常传输数据。QUIC也是需要三次握手来建立连接的,目的是为了协商连接ID。协商出连接ID后,后续传输时,双方只需要固定住连接 ID,从而实现连接迁移功能。Short Packet Header 中的 Packet Number
每个报文有独一无二的编号,并且严格递增。单调递增的设计,可以让数据包不再像 TCP 那样必须有序确认,当数据包Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动,从而解决了队头阻塞的问题。
当使用单调递增的设计并结合窗口滑动机制时,即使某个数据包丢失,接收方可以继续接收后续的数据包,而不会因等待丢失的数据包而发生队头阻塞。接收方能够识别出已丢失的数据包,并通知发送方进行重传,而发送方则可以继续发送新的数据包。这种机制提高了网络的吞吐量和效率,减少了传输延迟。这与传统的TCP协议中的严格有序确认机制有所不同,TCP需要按顺序等待所有数据包的确认,因此可能会导致队头阻塞。
QUIC Frame Header:一个 Packet 报文中可以存放多个 QUIC Frame。用于传输的Stream Frame有Stream ID、Offset和length字段,Stream ID用于多个并发传输的 HTTP 消息,通过不同的 Stream ID 加以区别、Offset字段类似于 TCP 协议中的 Seq 序号,保证数据的顺序性和可靠性;Length标识了 Frame 数据的长度。如果发生丢包了进行重传,通过比较两个数据包的Stream ID 与 Stream Offset,如果都是一致,就说明这两个数据包的内容一致。
所以,QUIC 通过单向递增的 Packet Number,配合 Stream ID 与 Offset 字段信息,可以支持乱序确认而不影响数据包的正确组装,摆脱了TCP必须按顺序确认的限制。