HTTP 已不再是全基于 TCP 了,QUIC 的发展终将带来 HTTP3
互联网的世界绝大部分的数据传输都是基于 HTTP 协议。自从 1990 年伯纳斯·李发明这 超文本传输协议(HTTP, HyperText Transfer Protocol) 后,于 1999 年 IETF 才正式发布 HTTP1.1(RFC 2616) 协议版本,而这个版本一用就是 15 年,至 2015 年 IETF 才正式发布 HTTP2(RFC 7540) 协议版本。其中 HTTP2 相比 HTTP1.1 的优化,我将会专门写个文章详细说明下。而今天我们会谈未来的 HTTP 协议 – QUIC/HTTP3。
- 本文将实现支持 QUIC/HTTP3 协议站点: https://http3.godjiyi.cn:9445/
- 个人实现 HTTP1.1/HTTP2/HTTP3 速度对比示例: https://demo.godjiyi.cn
- 开源 QUIC 支持项目: https://github.com/jiyiren/quic-web
视频示例:
协议截图:
QUIC 与 HTTP3
相信大家很早听说的下一代协议是 QUIC, 即 Quick UDP Internet Connections,意为快速UDP网络连接。该协议最早是由谷歌于 2013 推出的,项目首页: https://www.chromium.org/quic,并且在谷歌自家的 Youtube 和搜索引擎上试验,有兴趣的可以看下 The QUIC Transport Protocol - Design and Internet-Scale Deployment 这篇谷歌发表的论文。下图是谷歌应用 QUIC 于搜索引擎的的搜索延迟降低的百分比。(标1的地方是当时谷歌发现了 Bug,到 标2处修复后重新上线。标3处则是谷歌进行了一次优化,所以性能有了逐步提高) 整体上能降低搜索 6% 的延迟。
正因为 QUIC 的优势(为什么会有这优势,下面会进行说明),谷歌已经逐步将 QUIC 推广到自家的各个服务中了。
而当时 IETF 组织正忙于 HTTP2 协议的标准化,最终于2015年5月正式发布 HTTP2 规范(RFC 7540)。在 HTTP2 标准化完后,IETF 终于有时间进行下一代 HTTP 标准化,也就是 HTTP3。 而谷歌也有意将 QUIC 作为普适性协议进行推广。因而,于同年6月,谷歌提交 QUIC 草案给 IETF,以期作为下一代 HTTP 协议标准进行普及。
至 2018年,IETF组织中专门制定 HTTP 协议的组织(HTTP WG)正式确定将基于 QUIC 的 HTTP (HTTP Over QUIC) 作为下一代 HTTP 协议,并重命名为 HTTP3。并且 HTTPWG 认为标准化的 QUIC 协议应该支持 HTTP 以外的应用层协议。因此,IETF 将 QUIC 作为单独的传输层进行标准化,并成立了专门的 QUIC 协议标准化小组。
这里 QUIC 出现的频次较多,由于历史原因,导致大家会很难理解 QUIC 的具体含义,这里着重讲解下。
- HTTP3 确立标准化之前,QUIC 代表的都是谷歌的 QUIC,表示完整的 HTTP 实现,其又分为两种;
- HTTP2 协议标准化之前: 传输层 UDP 实现类 TCP 特性协议 + Spedy;
- HTTP2 协议标准化之后: 传输层 UDP 实现类 TCP 特性协议 + HTTP2;
- HTTP3 确立标准化之后,QUIC 既指代谷歌的 QUIC 也指代 IETF 的 QUIC, IETF 的 QUIC 仅仅表示传输层 QUIC,不包含应用层的实现;
为便于更好地区分 HTTP3 标准化前后两种 QUIC,现在,一般我们现在将谷歌的 QUIC 改称为 gQUIC,而 QUIC 则仅仅指代 IETF 的传输层 QUIC。文字不好理解,我特意画了张图。
虽然现在我们知道这 QUIC 应该指 IETF 的基于 UDP 的上层 “传输层协议”,但是由于 HTTP3 还没有出正式标准,且了解 IETF 中规范的 QUIC 标准很少,因此互联网上所说的 QUIC 一般都是 gQUIC。下文除非特别说明,QUIC 一律指 gQUIC。
QUIC/HTTP3 特性
对于 QUIC 的特性这里简单说下,以后会对每个点进行详细解释。
我们直接看谷歌 QUIC 官方首页:https://www.chromium.org/quic
一共总结四点:
- 大大减少建立连接时间;
- 增强的拥塞控制;
- 无队头阻塞的多路复用;
- 连接迁移;
通过整理了网上的特性说明,我将转换了下说法:
- 1/0 RTT;
- 优化拥塞控制;
- 无队头阻塞;
- 连接迁移;
对应的图示如下:
1/0 RTT
RTT 是指互联网上两个点建立连接的一次往返时间(round-trip time)。QUIC 建立握手的时间能达到 1 或 0 RTT。这是因为原有的 HTTP 是基于 TCP 的方式中:
- ① 裸 HTTP 需要 1.5 RTT;
- ② HTTPS 方式需要 3 RTT;
而 QUIC 则是基于 UDP 的,UDP 无需建立握手就能传输数据,那 1 RTT 只指 SSL 的建立时间。因此建立连接效率比原有 HTTP 快。这个我会专门写篇文章介绍。
而裸 HTTP 是不安全的,谷歌表示未来的协议都将默认加入安全传输 SSL 协议,因此 QUIC 本身就是要基于加密的,目前的大多数 QUIC 协议的实现也都默认含有加密的,因此,对于 QUIC 的对比,一般都是以 HTTPS 进行对比的。
优化拥塞控制
我们知道 TCP 的拥塞控制是内嵌于操作系统的,Linux 内核从 2.6.19 开始就是用 Cubic 拥塞控制算法。而谷歌于 2016 年发明了全新的 TCP 拥塞控制算法 – BBR (Bottleneck Bandwidth and RTT),这个已经验证是比 Cubic 性能更好的拥塞控制算法。因此,Linux 内核从 4.19 开始加入了 BBR 算法。
每一次的拥塞控制算法的更新都要更新内核,这使得新算法的迭代和普及极其缓慢。而 QUIC 协议则是基于 UDP 实现的类似 TCP 的协议,诸如有序控制、拥塞避免、拥塞控制都进行了重新实现。从宏观上来看,QUIC 则就是应用层协议,这对于拥塞控制算法的更新极其容易,不用更新操作系统。
此外 QUIC 中的拥塞控制是可拔插式的,这可更进一步优化和迭代各种新的拥塞控制算法。这也是 QUIC 极具吸引人的地方。
无队头阻塞
这里的消除队头阻塞在 QUIC 上是彻底地消除了。我们都知道 HTTP2 协议的规范上也说了消除队头阻塞。但那仅仅是消除了 HTTP 连接的队头阻塞,而根本上的 TCP 队头阻塞是没有消除的。因为只要基于 TCP 就铁定有 TCP 队头阻塞的。而 QUIC 是基于 UDP 的,非面向连接的,从而自动消除 TCP 队头阻塞。
- 多路复用是 HTTP2 的一大特定,也是相比 HTTP1.1 的提升体现。一个 web 站点在使用 HTTP2 协议时,只需要建立一个 TCP 连接,所有的数据通过帧进行发送,多个 HTTP 连接里的帧可以并行通过一个 TCP 连接发送。而原有的 HTTP1.1 则是一个 HTTP 连接就只能在一个 TCP 连接里发送,多个 HTTP 连接不能并行发送。一般 Chrome 浏览器对于 HTTP1.1 协议允许一个网站建立最多 6 个 TCP 连接。
- 虽然 HTTP2 的多路复用可解决 HTTP 连接并行问题,但解决不了 TCP 的队头阻塞问题。我们知道 TCP 需要包有序到达,当无序的时候,接收方会等待缺少的包,直至包到达。这是 TCP 的优点,也是缺点。
- 谷歌为了解决 TCP 握手和这种天生的缺陷,就基于 UDP 实现了类 TCP 各种特性的新协议,并将此协议融入 QUIC,这也就是 QUIC 天生就无队头阻塞的原因。
连接迁移
连接迁移这个就是指手机在 4G/5G 流量网络与 WIFI 网络之间可以无缝切换,而无需重建连接。
我们知道原有的基于 TCP 的 HTTP 协议,在切换网络时,都需要我们的手机与服务器进行重新建立 TCP 连接,然后才能重新发送 HTTP 数据包。
而 QUIC 协议是基于 UDP 的,天生无面向连接之说,但是我们还是需要维持客户端与服务的逻辑连接的。QUIC 中在数据包的头部加了 ConnectionID,这样每个 UDP 包里都有同一个连接的 ID,即使手机从 4G 切为 WIFI 了,手机在发送包时,仍然正常发送,而服务器可以根据 ConnectionID 进行组装即可,这也就是无缝连接迁移。
废话不多说,看谷歌给的连接迁移 Demo: QUIC Connection Migration demo
构建 QUIC/HTTP3 服务
QUIC库选择
由于 HTTP3 协议还在制定中,目前还没有正式的标准出台,只有每年定期举行的会议会给出 Draft 手稿。 IETF 官方 QUIC 工作组有统计在协议设计期间的各种实现库:
大家可以看下,我自己对比了比较常用和著名的库,表格如下,希望对大家选择有帮助。
今天我们先用 openlitespeed 库进行部署支持 QUIC 协议的 WEB 网站。因为该库官网放出性能是 Nginx 的几倍,且支持 gQUIC 和 HTTP3 协议。
QUIC 部署
openlitespeed 安装很简单,可以看官方教程: Install OpenLiteSpeed, 为防止部分人看不到,我记录了下:
先根据系统安装 repo 源:
1 | # CentOS 5 |
再执行安装命令(根据自己的系统选择安装命令)
1 | # CentOS |
安装完了就进行配置,配置说明请参考官方文档: Configuration
说实话,这个库是有后台的,是可视化配置,但是比较难用,需要自己熟悉才行。为避免大家浪费时间,我将整个服务安装好,并配置好了,构建了一个基础镜像:https://hub.docker.com/r/jiyiren/http-base-quic,如何配置自己的服务呢,下面简单讲下。
部署和配置代码已放 Github 上:https://github.com/jiyiren/quic-web
效果展示,我部署在我自己的服务器上: https://http3.godjiyi.cn:9445/ 。
并且我也写了一个 HTTP1.1 、HTTP2、HTTP3 速度加载对比示例: https://demo.godjiyi.cn
分别用 Chrome 浏览器和 Firefox 浏览器进行测试。这里说明下:
目前 Chrome 浏览器支持谷歌自家的 QUIC 协议,而谷歌家的 QUIC 原来单叫 QUIC,比如 gQUIC/46。在提交草案给 IETF 后,IETF 也开始了标准化,因此逐渐地谷歌开始将自家的 QUIC 像 IETF 标准靠,因此为 gQUIC-h3-50,相信以后 Chrome 会逐渐替换到 HTTP3 来。
而 Firefox 浏览器本身就和 Chrome 是竞争关系,所以虽然 QUIC 好,但没有国际组织的支持 Firefox 也不会支持的。而在谷歌提交草案后,得到了 IETF 的认可,并且 IETF 在进行标准化了,因此 Firefox 直接实现了 IETF 正规的 Draft 版本协议。所以 Firefox 浏览器标识时正规的 HTTP3 协议。
但不论怎样,这些协议思想一致,都是 UDP 进行传输,握手 RTT 很低,大家通过上面的速度加载对比就能看出来 HTTP3 的快速,当然在弱网情况下效果会更好点。
项目已放入 Github:https://github.com/jiyiren/quic-web 基于 Docker 构建,可以非常快速的构建自己的站点或 API。