参考文章: quic-是如何实现可靠传输的
QUIC 是如何实现可靠传输的?
Packet Header
Packet Header 两种:
- Long Packet Header 用于首次建立连接。
- Short Packet Header 用于日常传输数据。
重点:
- QUIC 三次握手建立连接,协商连接ID
- 日常传输数据的 Short Packet Header 只需要传输 Destination Connection ID
- Short Packet Header 的 Packet Number 是每个报文独一无二的编号,严格递增。
Packet N丢失,重传的 Packet N 的 Packet Nunmber 可能就是 N+M。
Packet Number 单调递增:
- 精确计算RTT,没有TCP重传的歧义性问题;
- 乱序确认
QUIC Frame Header
一个 Packet 报文中可以存放多个 QUIC Frame。
Frame 类似于 HTTP2 的设计。多种类型,功能不同,格式不同。
Stream Frame
- StreamID: 区分多个并发传输的消息。
- Offset:类似于 TCP 协议中 Seq 序号,保证数据的顺序性和可靠性。
- Length: Frame长度。
- data: 负载数据。
Frame Header 中 Packet Nunber 严格递增。丢失Packet N 和重传 Packet N+M 通过 Stream ID + Offset 确认一致,是否是相同数据包。
总的来说,QUIC通过单向递增的PacketNumber,配合StreamID与Offset字段信息,可以支持乱序确认而不影响数据包的正确组装,摆脱了TCP必须按顺序确认应答ACK的限制,解决了TCP因某个数据包重传而阻塞后续所有待发送数据包的问题。
QUIC 是如何解决 TCP 队头阻塞问题的?
TCP 队头阻塞 ---> 接收窗口的队头阻塞问题:接收方收到的数据范围必须在接收窗口范围内,如果收到超过接收窗口范围的数据,就会丢弃该数据。
导致接收窗口的对头阻塞的原因:因为 TCP 必须按序处理数据,只有在处理完有序的数据后,滑动窗口才能往前滑动,否则阻塞。
HTTP/2 的队头阻塞
HTTP/2 Stream实现HTTP并发传输,每一个Stream代表HTTP/1.1的请求响应。
不同Stream的帧可以乱序发送(可以并发不同的Stream),接收方通过每个帧头部的Stream ID有序组装成HTTP消息,而同一Stream内部的帧必须严格有序。
问题是:HTTP/2多个Stream请求在同一条TCP连接传输,意味着共用同一个TCP滑动窗口,那么当数据丢失,发生队头阻塞。
没有队头阻塞的 QUIC
QUIC 同样有 Stream,一条 QUIC 可以并发发送多个 HTTP请求(Sream)。
QUIC给每一个Stream分配一个独立的滑动窗口,使得一个连接上多个Stream之间没有依赖关系。
QUIC 是如何做流量控制的?
TCP 流量控制:接收方 告知 发送方,接收方 接收窗口的大小,发送方 可以控制发送的数据量。
QUIC 流量控制:
- window_update帧:告知对端自己可以接收的字节数,发送方不会超过。
- BlockFrame帧:告知对端由于流量控制被阻塞,无法发送数据。
QUIC里同一个Stream的数据要保证顺序,为实现可靠传输。
QUIC两种流量控制:
- Stream:Stream可以认为是一条HTTP,每个Stream都有独立的滑动窗口。
- Connection:限制连接中所有Stream想加起来的总字节数,防止发送方超过链接的缓冲容量。
Stream 级别的流量控制
初始状态:
如下图,接收方收到发送方发送的数据。存在多种情况:
- 已被上层读取数据包
- 未被上层读取数据包
- 丢失数据包
- 已收到但乱序的数据包
接收窗口的左边界取决于接收到的最大偏移字节数。此时:接收窗口 = 最大窗口数 - 接收到的最大偏移量。
- TCP 的接收窗口,当前面还有字节未接收但收到了后面的字节,依旧阻塞。
- QUIC的接收窗口,左边界滑动条件取决于接收到的最大偏移字节数。
如下图,当图中绿色部分数据超过最大接收窗口的一半后,最大接收窗口向右移动,接收窗口的右边界也向右扩展,同时给发送端发送 窗口更新帧,当发送方收到接收方的窗口更新帧后,发送窗口的右边界也会往右扩展。
绿色部分,是收到的顺序的数据,如果中途丢包,导致绿色部分的数据没有超过最大接收窗口的一半,那么接收窗口阻塞。只影响同一个stream。
Connection 流量控制
此时,其接收窗口是各个Stream接收窗口大小之和。
QUIC 对拥塞控制改进
QUIC协议当前默认使用了TCP的Cubic拥塞控制算法(我们熟知的慢开始、拥塞避免、快重传、快恢复策 略),同时也支持CubicBytes、Reno、RenoBytes、BBR、PCC等拥塞控制算法,相当于将TCP的拥塞控制算 法照搬过来了。
QUIC 更快的连接建立
HTTP/1 和 HTTP/2,TCP和TLS分层,需要先TCP握手,再TLS握手,需要3RTT延迟。如果Session会话复用,也要至少2个RTT。
QUIC内部包含TLS 1.3,在帧里携带TLS“记录”。只需要1个RTT即可同时完成建立连接与密钥协商,在第二次连接的时候,应用数据包可以和QUIC握手信息(链接信息+TLS信息)一起发送,达到 0-RTT。
QUIC 是如何迁移连接的?
基于TCP的HTTP协议,由于通过四元组(源ID,源端口,目的IP,目的端口)确定一条TCP连接。
QUIC 通过ID来标记连接的两个端点,客户端、服务器可以各自选择一组ID来标记自己。当移动设备网络发送变化,导致IP地址变化,只要仍保留上下文信息(比如连接ID,TLS密钥等),就可以继续复用原链接,消除重连的成本。