QUIC v2
最后更新于:2022-04-02 07:02:11
# QUIC v2
为了尽力专注于QUIC的核心特性,以及为了赶上发布进度,最初计划为核心协议一部分的几个特性已被推迟,计划到QUIC第二版或以后的版本中完成。
本文档的作者买的水晶球是山寨的,所以我们不能知道哪些特性会或者不会出现在第二版中。但我们可以谈谈那些在第一版中被标记为“之后做”的可能出现在第二版中的特性。
## 前向纠错(Forward Error Correction)
前向纠错(FEC)是一种通过向接收方发送冗余数据,使得接收方能快速识别出含有不明显错误的一种错误控制方式。
Google在它们的原版QUIC成果中实验过该特性,但由于实验结果不理想而已经去除。此特性可供QUIC v2讨论,但可能需要有人证明它在代价不大的情况下确实有用。
## 多路径(Multipath)
多路径意味着通信可以通过多个网络路径传输,以期最大化利用资源并增加冗余。
SCTP支持者可能有话说了,SCTP和现代TCP早就已经支持这一点。
## 不可靠数据
通过QUIC传输不可靠的数据流也得到过广泛讨论,这样QUIC就能在传统UDP风格的应用程序中作为代用品。
## 非HTTP适应
基于QUIC的DNS是早期被提出的非HTTP协议之一,这可能在QUIC v1和HTTP/3发布后得到更多的关注。但我想,如果我们拥有了这样的新型传输层协议,DNS远不是终点。
';
技术标准
最后更新于:2022-04-02 07:02:09
# 技术标准
以下是QUIC和HTTP/3各个部分的最新官方IETF草案列表。
## 不变性
[Version-Independent Properties of QUIC](https://tools.ietf.org/html/draft-ietf-quic-invariants-07)
## 传输层
[QUIC: A UDP-Based Multiplexed and Secure Transport](https://tools.ietf.org/html/draft-ietf-quic-transport-23)
## 自动恢复
[QUIC Loss Detection and Congestion Control](https://tools.ietf.org/html/draft-ietf-quic-recovery-23)
## TLS
[Using Transport Layer Security (TLS) to Secure QUIC](https://tools.ietf.org/html/draft-ietf-quic-tls-23)
## HTTP
[Hypertext Transfer Protocol (HTTP) over QUIC](https://tools.ietf.org/html/draft-ietf-quic-http-23)
## QPACK
[QPACK: Header Compression for HTTP over QUIC](https://tools.ietf.org/html/draft-ietf-quic-qpack-10)
';
常见批评
最后更新于:2022-04-02 07:02:07
# 常见批评
## UDP永远不会通
很多企业、运营商和组织对53端口(DNS)以外的UDP流量进行拦截或者限流,因为这些流量近来常被滥用于攻击。特别是一些现有的UDP协议和实现易受放大攻击(amplification attack)威胁,攻击者可以控制无辜的主机向受害者投放发送大量的流量。
QUIC内置了对放大攻击的缓解处理。它要求初始数据包不小于1200字节,并且协议中限制,服务器在未收到客户端回复的情况下,不能发送超过请求大小三倍的响应内容。
## 内核处理UDP很慢
我们必须承认这在2018年的今天是一个事实。当然,UDP技术会发展,这些年开发者对UDP的重视程度也不够,这些东西都自不必说了。
对于大多数客户端来说,这个程度的“缓慢”从未被觉察到。
## QUIC太吃CPU
类似上文的“UDP很慢”,一部分原因是TCP和TLS长期以来的成熟发展、改进,以及得到硬件协助,造成UDP看上去比较慢。
我们有理由期望这会随着时间得到改善。问题在于,这额外的CPU占用会对部署者带来多大的影响。
## 只有Google在弄
并非如此。Google通过大规模的部署证明,通过UDP部署这种协议可以正常运行且表现良好,这为IETF带来了初始的规范。
在那之后,很多公司和组织的人员都在这个利益方中立的IETF组织下推进标准化。在这个阶段,虽然Google的雇员也有参与,但Mozilla、Fastly、Cloudflare、Akamai、微软、Facebook、苹果等等很多公司的员工也参与进来,共同推进互联网的传输层协议。
## 进步太小
这个是一个观点,而不是批评。也许进步是很小,这可能与相距HTTP/2的发布很近有着关系,时间太短了。
HTTP/3在高丢包的网络中可能表现更好,它提供了更快的握手,所以能改善可感知和实际的延迟。这些进步足够推动人们在服务器和服务上部署HTTP/3的支持吗?时间以及未来的性能测试会给我们答案!
';
与HTTP/2的比较
最后更新于:2022-04-02 07:02:04
# HTTP/3与HTTP/2的比较
HTTP/3面向QUIC设计,QUIC是一个自己处理数据流的传输层协议。
HTTP/2面向TCP设计,因此数据流在HTTP层处理。
## 相似之处
这两个协议为客户端提供了几乎相同的功能集。
- 两者都提供数据流
- 两者都提供服务器推送
- 两者都有头部压缩,QPACK与HPACK的设计非常类似
- 两者都通过单一连接上的数据流提供复用
- 两者都提供数据流的优先度设置
## 不同之处
两个协议的主要不同点在于细节,不同之处主要由HTTP/3使用的QUIC带来。
- 得益于QUIC的0-RTT握手,HTTP/3可以提供更好的早期数据支持,而TCP快速打开和TLS通常只能传输更少的数据,且经常存在问题。
- 得益于QUIC,HTTP/3的握手速度比TCP+TLS快得多。
- HTTP/3不存在明文的不安全版本。尽管在互联网上很少见,HTTP/2还是可以不配合HTTPS来实现和使用。
- 通过ALPN拓展,HTTP/2可以直接在TLS握手时进行协商。HTTP/3基于QUIC,所以需要凭借响应中的 `Alt-Svc:` 头部来向客户端宣告。
';
服务器推送
最后更新于:2022-04-02 07:02:02
# HTTP/3服务器推送
HTTP/3的服务器推送与HTTP/2([RFC 7540](https://httpwg.org/specs/rfc7540.html))类似,但机制上有所不同。
服务器推送实际上就是对一个未曾发出的客户端请求做出响应!
服务器推送仅在客户端同意的前提下才允许发出。在HTTP/3中,客户端甚至能通过通告给服务器的最大推送流ID来设置所接受推送的次数限制。超出限制将导致连接错误。
如果服务器端认为客户端可能需要某个并未要求但应该有的额外资源,服务器可以通过请求流发送一个 `PUSH_PROMISE` 帧,使该推送请求看上去像是一个响应,然后通过新的流发送实际响应。
虽然客户端之前已经表示过推送可接受,但如果客户端认为适合,每个推送流仍可以随时取消,然后发送一个 `CANCEL_PUSH` 帧到服务器。
## 问题重重
自从推送这一特性在HTTP/2中讨论、开发、部署以来,它就备受争议、讨论和抨击。为了让它有用,人们付出了许多努力。
推送从来不是没有代价的,尽管它省了半个往返的延迟,它还是会消耗带宽。服务器也很难或不可能从高层面确定一个资源是否应该被推送过去。
';
优先度
最后更新于:2022-04-02 07:02:00
# HTTP/3优先度
HTTP/3中有一种帧是优先度(`PRIORITY`)。与HTTP/2中的类似,它用于设定一个流的优先度和依赖关系。
该帧可以设定一个流依赖于另一个流,也可以设定特定流的“权重”。
服务器应该只在一个流所依赖的所有流都被关闭,或者都无法取得进展时为该流分配资源。
一个流的权重是介于1到256之间的值,有着相同父系流的流**应该**按照权重的比例分配资源。
';
QUIC流与HTTP/3
最后更新于:2022-04-02 07:01:58
# QUIC流与HTTP/3
HTTP/3针对QUIC设计,所以它可以利用QUIC流的所有好处。而HTTP/2不得不在TCP之上构建它的数据流和复用概念。
通过HTTP/3传输的HTTP请求使用一系列的数据流完成。
## HTTP/3帧(frame)
HTTP/3意味着建立QUIC数据流,并将一系列帧发送给对方。HTTP/3中的数据帧种类不多且固定(截至2018年12月18日有九种)。最关键的帧可能是:
- HEADERS:发送压缩的HTTP头部
- DATA:发送二进制数据内容
- GOAWAY:请关闭此连接
## HTTP请求
客户端通过其发起的 双向 QUIC流来发送HTTP请求。
一个请求包括一个HEADERS帧,之后可能有一两种其他的帧:一系列的DATA帧,以及可能有一个作为末尾的HEADERS帧。
发送一个请求后,客户端会关闭该数据流以进行发出。
## HTTP响应
服务器在双向流上发回其HTTP响应。其中含有一个HEADERS帧,一系列DATA帧,末尾可能有一个HEADERS帧。
## QPACK头部
HEADERS含有用QPACK算法压缩的HTTP头部。QPACK与HTTP/2中的HPACK([RFC 7541](https://httpwg.org/specs/rfc7541.html))类似,并针对乱序流做了相应修改。
QPACK本身在两个端点间使用两个额外的单向QUIC流,用于在两个方向上传递动态表信息。
';
使用Alt-svc自举
最后更新于:2022-04-02 07:01:55
# 使用Alt-svc自举
# Alt-svc
替代服务(alternative service, Alt-svc:)头部和它相对应的 `ALT-SVC` HTTP/2帧并不是特别为QUIC和HTTP/3设计的。它是为了让服务器可以告诉客户端 *“看,我在这个主机的这个端口用这个协议提供相同的服务”* 而设计的。详见[RFC 7838](https://tools.ietf.org/html/rfc7838)。
如果初始连接使用的是HTTP/2(甚至HTTP/1),服务器可以响应并告诉客户端它可以再试试HTTP/3。连接可以指向相同主机或者不同但提供相同服务的主机。Alt-svc回复中有一个到期计时器,让客户端可以在指定的时间内使用建议的替代协议将后续的连接和请求直接发送给替代主机。
## 例子
一个HTTP服务器的响应中包含了如下的一个 `Alt-Svc:` 头部:
```
';
``` Alt-Svc: h3=":50781" ``` ``` 这指示了同一名称的主机在UDP端口50781提供HTTP/3服务。 然后,客户端可以尝试与该端口建立QUIC连接。如果成功,后续将通过该连接继续通信,代替初始的HTTP版本。
HTTPS:// URL
最后更新于:2022-04-02 07:01:53
# HTTPS:// URL
HTTP/3将使用`HTTPS://` URL履行。我们的世界里充斥着HTTPS URL,并且为新协议引入另一种URL方案被认为不切实际且完全不合理。如同HTTP/2一样,HTTP/3不会引入新的URL方案。
HTTP/2是传输HTTP的一种新方式,但是它还是基于TLS和TCP,这和HTTP/1一样。而在基于QUIC的HTTP/3中,情况更加复杂,它在一些重要的地方做了一些改变。
历史遗留下来的明文`HTTP://` URL的处理方式将保持原样,随着我们迈入安全传输更加普及的未来,它的使用可能会越来越少。对HTTP URL的请求不会升级为使用HTTP/3。在实践中,因为其他一些理由,它们也很少升级到HTTP/2。
## 初始连接
当尝试连接到一个全新的、未访问过的网站时,到HTTPS:// URL的连接可能必须通过TCP(也许会有并行的一个QUIC连接)。因为主机可能是一个不支持QUIC的传统服务器,或者链路之间可能有阻碍QUIC成功连接的中间设备。
现代的浏览器和服务器可能在首次握手时协商HTTP/2协议。在连接建立并且服务器响应客户端的HTTP请求时,服务器可以通告客户端它对HTTP/3的支持与偏好。
';
HTTP/3
最后更新于:2022-04-02 07:01:51
# HTTP/3
上文提到过,基于QUIC传输的第一个也是最基础的协议是HTTP。
就像HTTP/2是通过网络传输HTTP流量的一种新方式,HTTP/3是另一种通过网络传输HTTP的新方法。
HTTP的范例和概念没有改变。它含有头部(header)和正文(body),请求和回复,还有动词(verb)、Cookie和缓存。HTTP/3的主要改变是将这些报文比特传送到另一端的方式。
为了使HTTP可以通过QUIC传输,协议的某些方面要进行修改,修改的结果便是HTTP/3。这些必要修改是因QUIC与TCP在某些性质上的不同所致,修改包括:
- 在QUIC中,数据流由传输层本身提供,而在HTTP/2中,流由HTTP层完成。
- 由于数据流互相独立,HTTP/2中使用的头部压缩算法如果不做改动,会造成队头阻塞。
- QUIC流与HTTP/2略有不同。本书的HTTP/3章节会做详细介绍。
';
API
最后更新于:2022-04-02 07:01:49
# API
常规TCP与程序最成功的因素之一便是标准化的套接字(socket)API。其API有着定义良好的功能,使用它能让你轻松地在各操作系统之间移植程序,因为TCP采用同样的方式运作。
但QUIC不是如此。QUIC目前没有标准化的API。
使用QUIC时,你需要选择一个现有的库实现,并坚持使用它的API。这在某种程度上把应用“绑定”到了单一的库上。换库意味着使用另外一套API,这可能带来相当的工作量。
另外,由于QUIC一般在用户空间中实现,所以它不像现有的TCP和UDP套接字API那样能轻松扩展。使用QUIC意味着选择了套接字API之外的另一套API。
';
用户空间实现
最后更新于:2022-04-02 07:01:46
## 用户空间实现
在用户空间中实现一个传输层协议有助于协议的快速迭代,协议的演进更为容易,不需要客户端和服务器更新其操作系统内核才能部署新的版本。
QUIC本身没有固有的东西阻碍未来在操作系统内核中实现和提供QUIC协议。
### 众多的实现
在用户空间中实现一个新的传输层协议时,一个显而易见的效果是我们会看到很多独立的实现。
在可预见的未来,不同的应用程序可能包含(或基于)不同的HTTP/3和QUIC实现。
';
旋转比特位
最后更新于:2022-04-02 07:01:44
# 旋转比特位(Spin Bit)
在QUIC工作组的设计讨论中,最长的主题之一就是旋转比特位,人们花费了数百封邮件和数百个小时来讨论它。
旋转比特位的支持者认为,两个QUIC端点之间路径上的运营商和人员需要有办法来测量延迟。
反对者则反感此功能潜在的信息泄露。
## 旋转一个比特
QUIC连接的客户端、服务器这两个端点各为每一个QUIC连接维护一个旋转的值——0或1,在传送时候它们在报文中设置该值。
然后,在每一次往返时,连接双方都翻转这一比特的值。效果是观察者可以检测该比特字段的0与1脉冲。
这一观测只在发送方未被应用层或流量控制限制的情况下有效,并且网络上经过重新排序的数据包也会给数据带来噪声。
';
0-RTT
最后更新于:2022-04-02 07:01:41
# 0-RTT
先前已连接过一个服务器的客户端可能缓存来自该连接的某些参数,并在之后与该服务器建立一个无需等待握手完成就可以立即传输信息的**0-RTT**连接,从而减少建立新连接所必需的时间。
';
数据流
最后更新于:2022-04-02 07:01:38
# 数据流
数据流(Streams)在QUIC中提供了一个轻量级、有序的字节流的抽象化。
QUIC中有两种基本的数据流类型:
- 从发起者到对等端(Peer)的单向数据流。
- 双向均可发出数据的双向数据流。
连接端点的任意一方都可以建立这两种数据流,数据流之间可并行、交错地传输,并且可以被取消。
通过QUIC发送数据需要建立一个或多个数据流。
## 流量控制(Flow control)
每个数据流都有独立的流量控制,端点可以通过此实现内存控制和反压(back pressure)。数据流的创建本身也有流量控制,连接双方可以声明最多愿意创建几个流ID。
## 流标识符
数据流通过一个无符号的62比特整数标识,也称流ID。流ID的最低2位比特用于识别流的类型(单向或双向)和流的发起者。
流ID的最低1位比特(0x1)用于识别流的发起者。客户端发起双数(最低位置0)流,服务器发起单数(最低位置1)流。
第2个比特(0x2)识别单/双向流。单向流始终置1,双向流则置0。
## 流并发
QUIC允许任意数量的并发流。端点通过闲置最大流ID来控制并发活动的传入流数量。
每个端点指定自己的最大流ID数,并只对对等端端点有效。
## 收发数据
端点使用流来收发数据,这是流的最终用途。QUIC数据流是有序的字节流抽象。但是,不同流之间是无序的。
## 流优先度
如果正确设置了各流的优先度,流复用机制可以显著提升应用的效率。使用其他多路复用协议(如HTTP/2)的经验表明,有效的优先度划分策略对效率具有显著的正面影响。
QUIC本身没有提供交换优先度信息的报文。接收优先度信息依赖于使用QUIC的应用层。应用层可以定义所有复合其语义的优先度方案。
基于QUIC使用HTTP/3时,优先度信息在HTTP层完成。
';
使用TLS的连接
最后更新于:2022-04-02 07:01:36
# 使用TLS的连接
在初始的数据包建立连接之后,连接发起者会马上发一个加密的帧以开始安全层握手。安全层使用TLS 1.3协议。
在QUIC中,没有方法或机制避免使用TLS连接。该设计旨在使中间设备难以篡改数据包,防止协议僵化。
';
连接
最后更新于:2022-04-02 07:01:34
# 连接
QUIC连接是两个QUIC端点之间的单次会话(conversation)过程。QUIC建立连接时,加密算法的版本协商与传输层握手合并完成,以减小延迟。
在连接上实际传输数据时需要建立并使用一个或多个数据流。
## 连接ID(Connection ID)
每个连接过程都有一组连接标识符,或称连接ID,该ID用以识别该连接。每个端点各自选择连接ID。每个端点选择对方使用的连接ID。
连接ID的基本功能是确保底层协议(UDP、IP及其底层协议)的寻址变更不会使QUIC连接传输数据到错误的端点。
利用连接ID的优势,连接可以在IP地址和网络接口迁移的情况下得到保持——而这TCP永远做不到。举例来说,当用户的设备连接到一个Wi-Fi网络时,将进行中的下载从蜂窝网络连接转移到更快速的Wi-Fi连接。与此类似,当Wi-Fi连接不再可用时,将连接转移到蜂窝网络连接。
## 端口号
QUIC基于UDP建立,因此使用16比特的UDP端口号字段来区分传入的不同连接。
## 版本协商
客户端的QUIC连接请求会告知服务器所希望使用的QUIC协议版本,服务器端会回复一系列支持的版本供客户端选择。
';
QUIC工作原理
最后更新于:2022-04-02 07:01:32
# QUIC工作原理
本章节将解释QUIC传输层协议各基本模块的功能,而不会逐比特逐字节解释协议的报文。如果你想自己实现QUIC,这些介绍会加强你对协议的理解,但有关具体细节,请参考IETF的互联网草案(Internet Draft)和RFC。
1. 建立一个[连接](quic-connections.html)
2. 协商[安全的TLS连接](quic-tls.html)
3. 使用[数据流](quic-streams.html)
';
QUIC之上的非HTTP协议
最后更新于:2022-04-02 07:01:29
# QUIC之上的非HTTP协议
## 基于QUIC的非HTTP协议
基于QUIC传输非HTTP协议的相关工作已被推迟到第一版QUIC发布之后实现。
';
QUIC之上的HTTP协议
最后更新于:2022-04-02 07:01:27
# QUIC之上的HTTP协议
## HTTP/3
HTTP层以HTTP风格传输内容,包括使用QPACK进行HTTP头部压缩——这和HTTP/2中使用HPACK压缩头部类似。
HPACK算法依赖于数据流的有序交付,由于HTTP/3的数据流之间可能乱序,所以该算法需要修改才能使用。QPACK可被视作适用于QUIC版本的[HPACK](https://httpwg.org/specs/rfc7541.html)。
';