1. 引言
建立在 TCP 基础之上的 HTTP 是互联网上应用最为广泛的一种网络协议,诞生之初,主要就是为了将超文本标记语言 (HTML) 文档从 Web 服务器传送到客户端的浏览器。但是到了 Web 2.0 时代,HTML 页面变得越来越复杂,不仅仅单纯的是一些简单的文字和图片,同时有了层叠样式表 (Cascading Style Sheets,CSS),JavaScript (一种直译式脚本语言) 来丰富页面展示,随着 ajax 一种创建交互式网页应用的网页开发技术,英文全称: Asynchronous JavaScript And XML) 的出现,客户端又多了一种向服务器端获取数据的方法,这些其实都是基于 HTTP 协议的。同样到了移动互联网时代,页面可以在手机端浏览器里显示,但是和电脑端相比,手机端的网络情况更加复杂,经常涉及到蜂窝网络与无线局域网之间的切换,因此需要对 HTTP 进行深入理解并不断优化 。 SPDY (发音如英语 :speedy) 及 QUIC 就是在这样的背景下相继出现,接下来先分别介绍 HTTP 及 SPDY 的发展、QUIC 的特点,然后进行对比分析。
2. HTTP 及 SPDY
2.1 HTTP 1.x
HTTP/0.9 是一个过时的协议,它只接受 GET 一种请求方法,没有在网络传输中指定版本号,且不支持请求头。由于该版本不支持 POST 方法,因此客户端无法向服务器传递太多信息。
随后提出的 HTTP/1.0 是第一个指定版本号的 HTTP 协议版本,早期只是使用在一些较为简单的网页和网络请求上,而今主要是在代理服务器中使用。
HTTP/1.1 在 1999 年开始广泛应用于现在的各大浏览器网络请求中,同时也是当前使用最为广泛的 HTTP 协议。HTTP/1.1 与 HTTP/1.0 的主要区别为 :
(1) 缓存处理。在 HTTP/1.0 中主要使用 header 里的 If-Modified-Since, Expires作为缓存判断的标准,HTTP/1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
(2) 带宽优化及网络连接的使用。HTTP/1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象传过来了,并且不支持断点续传功能,HTTP/1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
(3) 错误通知的管理。在 HTTP/1.1 中新增了 24 个错误状态响应码,如 409 (Conflict) 表示请求的资源与资源的当前状态发生冲突 ; 410 (Gone) 表示服务器上的某个资源被永久性的删除。
(4) Host 头处理。在 HTTP/1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此请求消息中的 URL 并没有传递主机名 (hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个 IP 地址。HTTP/1.1 的请求消息和响应消息都应支持 Host 头域,且请求消息中如果没有 Host 头域会报告一个错误(400 Bad Request)。
(5) 长连接。HTTP/1.1 支持长连接 (Persistent Connection) 和请求的流水线 (Pipelining) 处理,在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟,在 HTTP/1.1 中默认开启 Connection: keep-alive,一定程度上弥补了 HTTP/1.0 每次请求都要创建连接的缺点。
尽管 HTTP/1.1 相比于 HTTP/1.0 有了很大的优化,但仍存在不少问题。
(1) 需要很多 TCP 连接来实现并发请求与响应,且在传输数据时每次都需要重新建立连接,这增加了大量的延迟时间并可能引起网络拥塞和高数据包丢失,导致更差的网络性能。
(2) 在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性。
(3) 头部信息 (header) 里携带的内容过大,在一定程度上增加了传输的成本,并且每次请求 header 基本不怎么变化,尤其在移动端环境下容易增加用户流量。
(4) 虽然 HTTP/1.1 支持了 keep-alive,来弥补多次创建连接产生的延迟,但是 keep-alive 使用多了同样会给服务端带来大量的性能压力。
(5) HTTP 请求严格由客户端发起,在网页加载很多嵌入对象时会严重影响性能,因为服务器只能在客户端发出请求后才能传输数据。
2.2 SPDY 与 HTTP/2
SPDY 是一种基于 TCP 的开放网络传输应用层协议,由 Google 开发,用来发送网页内容。设计 SPDY 的目的在于降低网页的加载时间,与 HTTP/1.1 相比,它在以下几方面作了改进。
(1) 降低延迟。针对 HTTP 高延迟的问题,SPDY 采取了多路复用 (multiplexing)。多路复用通过多个请求流共享一个 TCP 连接的方式,同时服务端也可通过一个连接发出多个应答流,提高了服务端性能。多路复用技术可以减少网络拥塞、降低延迟,同时提高了带宽的利用率。
(2) 请求优先级。多路复用带来一个新的问题是,在连接共享的基础之上有可能会导致关键请求被阻塞。SPDY 允许给每个请求设置优先级,这样重要的请求就会优先得到响应。比如浏览器加载首页,首页的 html 内容应该优先展示,之后才是各种静态资源文件,脚本文件等加载,这样可以保证用户能第一时间看到网页内容。
(3) header 压缩。HTTP 1.x 的 header 很多时候都是重复多余的。选择合适的压缩算法可以减小包的大小和数量,降低延迟。
(4) 基于 HTTPS 的加密协议传输,大大提高了传输数据的可靠性。SPDY中广泛应用了安全传输层协议 (Transport Layer Security,TLS) 加密,传输内容也均以 gzip 或 DEFLATE 格式压缩。
(5) 服务端推送。采用了 SPDY 的网页,在客户端发出一个资源请求时,服务端会把相关的资源主动推送到客户端而避免等待客户端再发出请求后响应。这可以减少页面加载时间。需要说明的是,SPDY 并不用于替换 HTTP,它只是修改了 HTTP 的请求与应答在网络上传输的方式; 这意味着只需增加一个 SPDY 传输层,现有的所有服务端应用均不用做任何修改。当使 用SPDY 的方式传输时,HTTP请求会被处理、标记简化和压缩。比如,每一个 SPDY 端点会持续跟踪每一个在之前的请求中已经发送的 HTTP 报文头部,从而避免重复发送还未改变的头部。而还未发送的报文的数据部分将在被压缩后被发送。SPDY 的构成如图 1 所示。
2015 年推出的 HTTP/2 大部分基于 SPDY 实现,主要区别为 :
(1) HTTP/2 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS。
(2) HTTP/2 消息头 (header) 的压缩算法采用 HPACK,而非SPDY 采用的 DEFLATE。由于 HTTP/2 推出时间不长,相较于 HTTP/1.1 应用范围还不广,但是未来肯定会逐渐取代 HTTP/1.1。
3 QUIC
3.1 HTTP/2 的局限性
除了 QUIC 是基于 UDP 实现,前面几种协议都是基于 TCP。TCP 因其面向连接、可靠传输等特点而被广泛采用,但在如今带宽越来越大的网络环境下,TCP 的局限性也制约了 HTTP/2 的性能,主要表现为以下两点。
(1) 数据传输前 TCP 先要进行“三次握手”,建立连接后才开始传输应用数据,这无疑增加了网络延时; 在采用 TLS 协议时需要交换密钥,这又增加了一次往返时延 (Round-Trip Time,RTT)。
(2) HOL (Head-of-line) blocking,前序包阻塞。TCP 保证有序传输,所以当一个数据包丢失时,其他所有的包都要等它重传整理后才会交给应用层,对于多路复用共享一个 TCP 连接的 SPDY 和 HTTP/2 来说,这无疑影响更大。
3.2 QUIC 的特点
QUIC 最主要的目标是减小网络传输延迟,所以选择了 UDP 作为传输层协议,它的主要优点有:
(1) QUIC 协议在创建连接握手时,只需要 1 到 2 个数据包即可。参考 TCP+TLS 协议的传输方式,QUIC 设计了类似 DTLS (Datagram Transport Layer Security,数据报传输安全层)的传输模型。这个模型大大简化了建立连接的过程,使得创建连接握手时只需 1 到 2 个数据包。对于无线网络来说,客户端和服务器之间的延时通常在 100ms 以上。传统 TCP+TLS 协议的传输方式,在创建连接时的4个数据包和QUIC协议的1个数据包相比,连接创建上就会多耗时 300ms 以上。图 2、图 3 分别为 TCP+TLS、QUIC 的握手示意图。
(2) 避免前序包阻塞。SPDY 和 HTTP/2 支持将页面的多个数据(如音频、图片等)通过一个 TCP 连接进行传输。该特性能够加快页面组件的传输速度,但是对于 TCP 协议来说,这会遇到前序包阻塞的问题。因此,即使逻辑上一个 TCP 连接上并行的在进行多路数据传输,其他毫无关联的数据也会因此阻塞。由于 UDP 协议没有严格的顺序,当一个数据包遇到问题需要重传时,只会影响该数据包对应的资源,其他独立的资源(如其他 CSS、JavaScript 文件)不会受到影响。QUIC 协议直接通过底层使用 UDP 协议天然的避免了该问题。
(3) QUIC协议有一个非常独特的特性,称为向前纠错 (Forward Error Correction,FEC),每个数据包除了它本身的内容之外,还包括了部分其他数据包的数据,因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。向前纠错牺牲了每个数据包可以发送数据的上限,但是减少了因为丢包导致的数据重传,因为数据重传将会消耗更多的时间(包括确认数据包丢失、请求重传、等待新数据包等步骤的时间消耗)。
(4) 底层协议切换到 UDP 协议之后的另一大好处是,连接不再依赖于来源 IP。对于 TCP 协议来说,标识一个 TCP 连接需要 4 个参数,即来源 IP、来源端口、目的 IP 和目的端口。其中的任一参数改变,TCP 连接就需要重新创建。这对于传统网络来说影响不大,因为来源和目的 IP 相对固定。但是在无线网络中,情况就大不相同了。设备在移动过程中,可能会因为网络切换(如从 WIFI 网络切换到 4G 网络环境),导致 TCP 连接需要重新创建。QUIC 协议使用了 UDP 协议,不再需要这四组参数。同时 QUIC 协议实现了自己的会话标记方式,称为连接 ID。当设备网络环境切换时,连接 ID 不会发生变化,因此无需重新进行握手。该特性除了可以减少无谓的连接重连之外,还可以充分利用设备的不同网络接口,进行资源的并行下载。因为虽然这些网络接口有不同的 IP,但只要他们能够共享连接 ID,就能够并行的从服务器下载数据。
QUIC 协议内置了 TLS 栈,实现了自己的传输加密层,同时QUIC 还包含了部分 HTTP/2 的实现 , 底层通过 UDP 协议替代了TCP,上层只需要一层用于和远程服务器交互的 HTTP/2 API。这是因为 QUIC 协议已经包含了多路复用和连接管理,HTTP API 只需要完成HTTP协议的解析即可。图 4 为协议层次对比图。
3 结束语
QUIC 通过一次 (通信双方从未建立连接) 甚至不需要往返握手就可建立连接,这大大降低了网络传输延迟。同时采用 UDP 底层协议避免了 HTTP/2 基于 TCP 的 HOL (前序包阻塞) 问题。今天,大多数人都会随身带着诸如智能手机等移动设备,在 TCP 中当网络环境发生变化时需要重新分配 IP 地址、建立连接,在未来这显然太慢了。QUIC 通过一个 64 bit 的 GUID (Globally Unique Identifier,全球唯一标识符) 来标记传输包,服务器可以通过它来区分来源端口,并且在QUIC连接断开后不需要往返握手来建立连接。
所有这些都使 QUIC 有着强大的吸引力和应用前景,或许会在某一天取代 TCP、HTTP,更有可能的是它们互相吸收对方的长处,共同发展。
参考文献
[1] Megyesi P, Krämer Z, Molnár S. How quick is QUIC[C] Communications (ICC), 2016 IEEE International Conference on. IEEE, 2016: 1-6.
[2] Biswal P, Gnawali O. Does QUIC make the Web faster[C] Global Communications Conference (GLOBECOM), 2016 IEEE. IEEE, 2016: 1-6.
[3] Gratzer F. QUIC-Quick UDP Internet Connections[J]. Future Internet (FI) and Innovative Internet Technologies and Mobile Communications (IITM), 2016, 39.
[4] Carlucci G, De Cicco L, Mascolo S. HTTP over UDP: an Experimental Investigation of QUIC[C] Proceedings of the 30th Annual ACM Symposium on Applied Computing. ACM, 2015: 609-614.