QUIC
quick udp internet connection
是由 google 提出的使用 udp 进行多路并发传输的协议
优势
Quic 相比现在广泛应用的 http2+tcp+tls 协议有如下优势
- 减少了 TCP 三次握手及 TLS 握手时间。
- 改进的拥塞控制。
- 避免队头阻塞的多路复用。
- 连接迁移。
- 前向冗余纠错。
0RTT建连
传输层和加密层总共只需要0RTT就可以建立连接。
因为其握手数据和HTTP数据一同发送,建连过程可以认为是0RTT的。
灵活的拥塞控制
QUIC默认使用了 TCP 协议的 Cubic 拥塞控制算法,同时也支持 CubicBytes, Reno, RenoBytes, BBR, PCC 等拥塞控制算法。
但其:
可插拔
- 该拥塞控制算法实现于应用层,不需要修改内核就可以对其快速迭代
- 同一程序的不同连接使用不同拥塞控制算法,针对不同用户做适配
- 变更算法只需要修改配置再重新加载,不需要停机
递增的packet number和维持顺序的stream offset
使用严格递增的packet number,即使是相同包的重发也递增。接收端就可以区分开这个包是重发的还是之前的。
避免了在计算RTT的时候引发的歧义问题,因为发送方RTT计算需要计算的边界是包发出和包收到两处,如果使用重发包的时刻作为左边界,收到ack的时刻作为右边界,万一这个ack是初始发出的包的而不是重发的那就统计小了。
SACK选项空间更大
QUIC的SACK选项空间256Bytes 对比TCP的30Bytes很大,能够提供更多已经收到segment的信息,方便发送端进行精度更高的选择重传
Ack Delay
Ack Delay是在接收端进行处理的时间,该时间也需要记录并发送,TCP的timestamp区域并不记录这个,计算的RTT理论上就更大不够准确。
QUIC在计算RTT时会减去Ack Delay
基于 stream 和 connecton 级别的流量控制
connection: TCP连接 ,复用:一个connection上可能有多个stream
stream: HTTP请求
QUIC 实现流量控制:
通过 window_update 帧告诉对端自己可以接收的字节数,这样发送方就不会发送超过这个数量的数据。
通过 BlockFrame 告诉对端由于流量控制被阻塞了,无法发送数据。
QUIC 的流量控制和 TCP 有点区别,TCP 为了保证可靠性,窗口左边沿向右滑动时的长度取决于已经确认的字节数。如果中间出现丢包,就算接收到了更大序号的 Segment,窗口也无法超过这个序列号。
但 QUIC 不同,就算此前有些 packet 没有接收到,它的滑动只取决于接收到的最大偏移字节数。
当读取端读取到未到达的包时,可以采取发特殊包的方法向发送端要。
没有队头阻塞的多路复用
QUIC 的多路复用和 HTTP2 类似。在一条 QUIC 连接上可以并发发送多个 HTTP 请求 (stream)。但是 QUIC 的多路复用相比 HTTP2 有一个很大的优势。
QUIC 一个连接上的多个 stream 之间没有依赖。这样假如 stream2 丢了一个 udp packet,也只会影响 stream2 的处理。不会影响 stream2 之前及之后的 stream 的处理。
HTTP2的多个stream即使后面stream已经全部到达,前面stream出现丢包也需要后面stream跟着一起等待才能读取。
HTTP2使用的TLS协议中最小单位是Record,最大不能超过 16K,由于一个 record 必须经过数据一致性校验才能进行加解密,所以一个 16K 的 record,就算丢了一个字节,也会导致已经接收到的 15.99K 数据无法处理,因为它不完整。
QUIC 最基本的传输单元是 Packet,不会超过 MTU 的大小,整个加密和认证过程都是基于 Packet 的,不会跨越多个 Packet。这样就能避免 TLS 协议存在的队头阻塞。
Stream 之间相互独立,比如 Stream2 丢了一个 Pakcet,不会影响 Stream3 和 Stream4。不存在 TCP 队头阻塞。
加密认证的报文
QUIC除了个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的。
而TCP报文头部完全裸露。
连接迁移
TCP连接以四元组标识(俩IP和端口),任意一个或多个变化就发生断连。针对 TCP 的连接变化,MPTCP其实已经有了解决方案,但是由于 MPTCP 需要操作系统及网络协议栈支持,部署阻力非常大,目前并不适用。
任何一条 QUIC 连接不再以四元组标识,而是以一个 64 位的随机数作为 ID 来标识,这样就算 IP 或者端口发生变化时,只要 ID 不变,这条连接依然维持着,上层业务逻辑感知不到变化,不会中断,也就不需要重连。
由于这个 ID 是客户端随机产生的,并且长度有 64 位,所以冲突概率非常低。