27 HTTP/3

Posted by CodingWithAlice on May 6, 2021

27 HTTP/3

一篇写得很细的博文:HTTP3.0和QUIC协议那些事

  • 总结

    1、HTTP/3 基于 QUIC 协议,完全解决了队头阻塞 问题,弱网环境下的表现会优于 HTTP/2

    2、QUIC 是一个新的 传输层协议,建立在 UDP 之上,实现了可靠传输

    3、QUIC 内含了 TLS1.3,只能加密通信,支持 0-RTT 快速建连

    4、QUIC 的连接使用不透明的连接 ID,不绑定在 IP 地址 + 端口 上,支持连接迁移

    5、QUIC 的流与 HTTP/2 的流很相似,但 分为双向流和单向流

    6、HTTP/3 没有指定默认端口号,需要用 HTTP/2 的 扩展帧Alt-Svc 来发现

为什么说HTTP2 没有完全解决队头堵塞呢?

HTTP/2 虽然使用帧、流、多路复用,(在应用层)没有了队头阻塞【,但这些手段都是在 应用层 里,而在下层传输层的 TCP 协议 里,还是会发生队头阻塞

  • 队头阻塞的解决方案

    • HTTP/1.1 存在 HTTP 层和 TCP 层两个层次的队头阻塞
    • HTTP/2 - 多路复用机制 解决了 HTTP 层(应用层)的队头阻塞,TCP 层仍存在

    img

  • TCP队头堵塞 - TCP拥塞控制的四个算法:慢启动,拥塞避免,快速重传,快速恢复

    当 HTTP/2 把多个 请求 - 响应 分解成流,交给 TCP 后,TCP 会再拆成更小的包 segment 依次发送

    队头堵塞:TCP 为了保证可靠传输,有个特别的 丢包重传 机制,丢失的包必须要 等待重新传输确认,其他的包即使已经收到了,也只能放在缓冲区里,上层的应用拿不出来,只能干着急【一个数据包影响了一堆数据包,它不来大家都走不了】

    image-20210506201914250

HTTP/3 – HTTP over QUIC

QUIC - 传输层协议(和TCP平级)

HTTP/3 将 TCP 更换为 UDP – 因为 UDP 是 无序的,包之间没有依赖关系,所以就从根本上解决了队头阻塞

image-20210506104646912

着重对比下 HTTP/2 和 HTTP/3如下:

img

QUIC 协议特点

1、QUIC 基于 UDP,而 UDP 是 无连接 的,根本就不需要 握手和挥手,所以天生就要比 TCP 快

2、引入了类似 HTTP/2 的 多路复用,单个 是有序的,可能会因为丢包而阻塞,但其他 不会受到影响

QUIC 一个连接上的多个 stream 之间没有依赖。这样假如 stream2 丢了一个 udp packet,也只会影响 stream2 的处理。不会影响 stream2 之前及之后的 stream 的处理

3、QUIC 直接应用了 TLS1.3,获得了 0-RTT、1-RTT 连接的好处

QUIC协议可以实现在第一个包就可以包含有效的应用数据,从而实现0RTT(前提条件:非首次传输)

4、QUIC 全面采用加密通信,可以很好地抵御窜改和协议僵化

5、QUIC 并不是建立在 TLS 之上,而是内部 包含了 TLS。它使用自己的帧 接管 了 TLS 里的 记录,握手消息、警报消息都不使用 TLS 记录,直接封装成 QUIC 的帧发送,省掉了一次开销

QUIC 内部细节

  • QUIC 的基本数据传输单位是包(packet)和帧(frame),一个包由多个帧组成,包面向的是连接,帧面向的是流

  • QUIC 使用 不透明的连接 ID 来标记通信的两个端点,客户端和服务器可以自行选择一组 ID 来标记自己,这样就 解除了 TCP 里连接对IP 地址 + 端口 的强绑定,支持 连接迁移

    img

    举例:手机会自动由 4G 切换到 WiFi –> 这时 IP 地址会发生变化,TCP 就必须重新建立连接;而 QUIC 连接里的两端连接 ID 不会变,所以连接在“逻辑上”没有中断,它就可以在新的 IP 地址上继续使用之前的连接,消除重连的成本,实现连接的无缝迁移

  • 解析结构细节:

image-20210506105008802

1、帧类型

PING、ACK 等帧用于管理连接,而 STREAM 帧专门用来实现流

2、流标识符

HTTP/2 里的流都是双向的,而 QUIC 则分为双向流和单向流

流 ID 还保留了最低两位用作标志,第 1 位标记流的发起者,0 -客户端,1 - 服务器;第 2 位标记流的方向,0 - 双向流,1 - 单向流。

HTTP/3 协议

因为 QUIC 本身就已经支持了加密、流和多路复用,所以 HTTP/3 把 流控制 都交给 QUIC 去做。

  • 流控制

    调用的不再是 TLS 的安全接口,也不是 Socket API,而是专门的 QUIC 函数

  • HTTP/3 的帧结构

    帧头:只有两个字段 类型和长度,最小只需要两个字节

    image-20210506105134840

  • 头部压缩算法

    升级成了QPACK,在流上发送 HEADERS 帧时 不能更新字段,只能引用,索引表的更新需要在 专门的单向流 上发送指令来管理,解决了 HPACK 的队头阻塞问题

  • HTTP/3 服务发现 - 利用HTTP/2 里的扩展帧

    –> 浏览器需要先用 HTTP/2 协议连接服务器

    –> 服务器可以在启动 HTTP/2 连接后发送一个 Alt-Svc 帧,包含一个 h3=host:port 的字符串,告诉浏览器在另一个端点上提供等价的 HTTP/3 服务

    –> 浏览器收到 Alt-Svc 帧,会使用 QUIC 异步连接指定的端口,如果连接成功,就会断开 HTTP/2 连接,改用新的 HTTP/3 收发数据