从HTTP到HTTP/3的发展简史

2020 年 11 月 19 日

从HTTP到HTTP/3的发展简史

本文最初发布于 scorpil.com 网站,经原作者授权由 InfoQ 中文站翻译并分享。


虽然 HTTP/3 规范仍处于起草阶段,但最新版本的 Chrome 浏览器已经默认支持它了。Chrome 拥有约 70%的浏览器市场份额,所以,可以说 HTTP/3 已经进入主流世界。



这一基础协议的最新修订版旨在让 Web 更加高效、安全并缩短内容交付延迟。从某些角度来说,它是 HTTP2 的完善:通过使用新的专用协议 QUIC 替换基础 TCP 协议来解决和之前类似的目标。


想要弄明白 QUIC 的优点,最好的办法是讲清楚 TCP 作为 HTTP 请求的传输方式有哪些不足之处。


为此,我们将从头开始细细道来。


HTTP:起源


1991 年,当蒂姆·伯纳斯·李爵士设计出一个简单的单行超文本交换协议时,TCP 已经是一个古老而可靠的协议了。前者的原始定义文档(也就是后人熟知的 HTTP 0.9)特别提到 TCP 是首选的(尽管并非唯一的)传输协议:


注意:HTTP当前运行在TCP上,但也可以运行在任何面向连接的服务上。


当然,HTTP 的这个概念验证版本与我们现在所知道和喜欢的 HTTP 几乎没有相似之处。没有标头,也没有状态码。典型的请求只有GET/path而已。响应仅包含 HTML,且 TCP 连接关闭就会结束。


由于浏览器尚未流行,因此用户需要直接阅读 HTML。可以用它链接到其他资源,但是在这个 HTML 早期版本中存在的所有标签都不会异步请求其他资源。一个 HTTP 请求就传递了一个完整的、自给自足的页面。


HTTP/1.0 出现


在随后几年中,互联网迎来爆炸式的发展,尽管传输 HTML 仍然是 HTTP 的主要特色,但它逐渐发展成一种可扩展且灵活的通用协议。HTTP 的三大重要更新奠定了这一演变的基础:


  • 方法的引入使客户能确定其想要执行操作的类型。例如,引入POST是为了允许客户端将数据发送到服务器以处理和存储;

  • 状态码为客户端提供了一种确认服务器已成功处理请求的方法——如果处理失败,则可以用它了解发生了哪种错误;

  • 标头增加了将结构化文本元数据附加到可以修改客户端或服务器行为的请求和响应上的功能。例如,编码和内容类型头使HTTP不仅可以传输HTML,还可以传输任何类型的负载。“压缩”标头允许客户端和服务器协商支持的压缩格式,从而减少了通过连接传输的数据量。


同时,HTML 也不断进化,支持了图像、样式和其他链接资源。


现在,浏览器需要执行多个请求来显示一个网页,而原始的“按请求连接”架构是做不到的。建立和终止 TCP 连接涉及大量的数据包来回交换,因此在延迟开销方面相对昂贵。网页不见得一定由单个文本文件组成,但是随着每页请求数量的增加,延迟也随之增加。


下图说明了每建立一个新的 TCP 连接涉及多少请求开销。



TCP 连接需要三个请求才能建立连接,四个请求可以完全关闭


人们创建了一个“连接”标头来解决这个问题。客户端发送带有“connection:keep-alive”标头的请求,以表明意图为后续请求保持 TCP 连接的打开状态。如果服务器理解此标头并同意遵守该标头,则其响应还将包含“connection:keep-alive”标头。


这样,双方都保持 TCP 通道打开并使用它进行后续通信,直到任何一方决定关闭它为止。随着 SSL/TLS 加密技术的发展,这一点变得更加重要,因为协商加密算法和交换加密密钥需要在每个连接上增加一个请求/响应周期。



单个 TCP 连接可以通过“connection:keep-alive”标头重用于多个请求


当时,许多 HTTP 改进都是自发出现的。当流行的浏览器或服务器应用程序需要新的 HTTP 功能时,它们会自己实现该功能,并希望其他各方也能效仿。具有讽刺意味的是,去中心化的 Web 需要一个中心化的管理机构来避免碎片化造成的不兼容问题。


该协议的最初创建者蒂姆·伯纳斯·李(TimBerners-Lee)意识到了这种危险,并于 1994 年成立了万维网联盟(W3C),该联盟与互联网工程任务组(IETF)一起致力于规范互联网的技术栈。作为为已有环境带来更多规范的第一步,他们记录了当时 HTTP 中最常用的一些功能,并将其命名为 HTTP/1.0 协议。


但是,由于这种“规范”描述的是多种多样的,通常在“实践”中用法不一致的技术,因此它从未获得过标准地位。相比之下,关于 HTTP 协议新版本的工作已经开始了。


HTTP/1.1 的标准化


HTTP/1.1 修复了 HTTP/1.0 的不一致之处,并调整了协议,使其在新的 Web 生态系统中具备更好的性能表现。新版引入的两个最关键的更改是默认使用持久 TCP 连接(保持活动状态)和 HTTP 管线化。


HTTP 管线化的意思就是客户端无需在发送后续 HTTP 请求之前等待服务器响应请求。此功能可以更有效地利用带宽并减少延迟,但它的改进空间甚至更大。HTTP 管线化仍要求服务器按照接收到的请求顺序进行响应,因此,如果管线化中的单个请求执行得很慢,则对客户端的所有后续响应都将相应地延迟下去。这个问题被称为线头阻塞。



由于首先请求了 large-picture.jpg,因此阻止了 style.css 的发布


在这个时候,Web 正在获得越来越多的交互功能。Web 2.0 指日可待,一些网页包含数十个甚至数百个外部资源。为解决线头阻塞,并降低页面加载速度,客户端会在每个主机上建立多个 TCP 连接。当然,连接开销并没有消失不见。实际上情况变得更糟了,因为越来越多的应用程序开始使用 SSL/TLS 加密 HTTP 通信。因此,大多数浏览器都设置了最大可能同时连接数的限制,以寻求微妙的平衡。


许多较大的 Web 服务已经意识到,现有的限制对于其交互极为繁重的 Web 应用程序来说太过严格,因此它们会通过多个域名分发其应用程序来“玩弄系统”。这种办法好歹起效了,但是解决方案根本谈不上优雅。


尽管存在一些缺点,但是 HTTP/1.0 和 HTTP/1.1 的简单性使它们获得了广泛的成功,并且十多年来,没有人认真地尝试过改变它们。


SPDY 和 HTTP/2


谷歌在 2008 年发布了 Chrome 浏览器,这种浏览器因其快速和创新而迅速流行。它使谷歌在互联网技术问题上获得了强大的话语权。在 2010 年代初期,谷歌在 Chrome 中增加了对其 Web 协议 SPDY 的支持。


HTTP/2 标准基于 SPDY,并进行了一些改进。HTTP/2 通过在单个打开的 TCP 连接上多路复用 HTTP 请求,解决了线头阻塞问题。这允许服务器以任何顺序响应请求,然后客户端可以在接收到响应时重新组合响应,从而在单个连接中加快整个交换的速度。



由于 HTTP/2 可以多路传输,因此在 large-picture.jpg 之前返回了 style.css


实际上,使用 HTTP/2 服务器甚至可以在请求之前就将资源提供给客户端!举个例子,如果服务器知道客户端很可能需要样式表来显示 HTML 页面,它可以将 CSS“推”到客户端,而无需等待相应的请求。虽然这从理论上讲是有益的,但此功能在实践中很少见,因为它需要服务器了解其服务的 HTML 结构,但这种情况很少发生。


除了请求正文以外,HTTP/2 还允许压缩请求标头,这进一步减少了通过网络传输的数据量。


HTTP/2 解决了 Web 上的许多问题,但不是全部。在 TCP 协议级别上仍然存在类似类型的线头问题,而 TCP 仍然是 Web 的基础构建块。当 TCP 数据包在传输过程中丢失时,在服务器重新发送丢失的数据包之前,接收方无法确认传入的数据包。由于 TCP 在设计上不遵循 HTTP 之类的高级协议,因此单个丢失的数据包将阻塞所有进行中的 HTTP 请求的流,直到重新发送丢失的数据为止。这个问题在不可靠的连接上尤为突出,这在无处不在的移动设备时代并不罕见。


HTTP/3 革命


由于 HTTP/2 的问题不能仅靠应用程序层来解决,因此协议的新迭代必须更新传输层。但是,创建新的传输层协议并非易事。传输协议需要硬件供应商的支持,并且需要大多数网络运营商的部署才能普及。由于此事涉及的成本和工作量,运营商们不愿进行更新。以 IPv6 为例:它是 24 年前推出的,但如今距离获得普遍支持还有很远的距离。


幸运的是还有另一种选择。UDP 协议与 TCP 一样得到广泛支持,但前者足够简单,可以作为在其之上运行的自定义协议的基础。UDP 数据包是一劳永逸的:没有握手、持久连接或错误校正。HTTP3 背后的主要思想是放弃 TCP,转而使用基于 UDP 的 QUIC 协议。QUIC 以对 Web 环境有意义的方式添加了许多必要的功能(包括以前由 TCP 提供的功能,以及更多功能)。


与 HTTP2 在技术上允许未加密的通信不同,QUIC 严格要求加密后才能建立连接。此外,加密不仅适用于 HTTP 负载,还适用于流经连接的所有数据,从而避免了一大堆安全问题。建立持久连接、协商加密协议,甚至发送第一批数据都被合并到 QUIC 中的单个请求/响应周期中,从而大大减少了连接等待时间。如果客户端具有本地缓存​​的密码参数,则可以通过简化的握手(0-RTT)重新建立与已知主机的连接。


为了解决传输级别的线头阻塞问题,通过 QUIC 连接传输的数据被分为一些流。流是持久性 QUIC 连接中短暂、独立的“子连接”。每个流都处理自己的错误纠正和传递保证,但使用连接全局压缩和加密属性。每个客户端发起的 HTTP 请求都在单独的流上运行,因此丢失数据包不会影响其他流/请求的数据传输。



HTTP/3 将连接分为单独的流


UDP 是一种无状态协议(持久连接只是其之上的抽象),使 QUIC 能够支持一些很大程度上忽略了数据包传递复杂性的功能。例如,从理论上讲,客户端更改其 IP 地址中间连接(例如智能手机从移动网络跳转到家庭 wifi)时不应中断连接,因为该协议允许在不同 IP 地址之间迁移而无需重新连接。


QUIC 协议的所有现有实现当前都在用户空间,而不是 OS 内核中运行。由于客户端(例如浏览器)和服务器的更新通常比操作系统内核更新的频率更高,因此人们希望可以藉此更快地采用新功能。


HTTP/3 存在的问题


我认为 HTTP/3 标准虽然是向更快、更安全的互联网迈出的一大步,但它并不完美。它的某些问题是由其新颖性引起的,而其他一些问题似乎是该协议固有的。


TCP 协议已经存在了很长时间,对于路由器来说很容易理解。它具有清晰的未加密标记(用于建立和关闭连接),可用于跟踪和控制现有会话。在网络硬件学会了解新协议之前,它将把 QUIC 流量简单地看作独立的 UDP 数据包流,这将使网络配置更加棘手。


从客户端缓存“恢复”连接的能力使该协议很容易遭受重播攻击:在某些情况下,恶意攻击者可以重新发送以前捕获的数据包,这些数据包将被服务器解释为有效的,来自受害者的。像那些提供静态内容的 Web 服务器一样,许多 Web 服务器不会受到此类攻击的伤害。对于身处易受攻击环境的应用程序来说,必须要记住禁用 0-RTT 功能。


这就是 HTTP 到今天为止的故事。我认为 HTTP/3 是向前迈出的一大步,并且当然希望 HTTP/3 在不久的将来会被广泛采用。


原文链接:


https://scorpil.com/post/the-long-road-to-http3/


2020 年 11 月 19 日 12:391575
用户头像

发布了 461 篇内容, 共 169.7 次阅读, 收获喜欢 970 次。

关注

评论 1 条评论

发布
用户头像
http2 居然没有出关于隐私方面的加强。依然依靠 tls 协议,也就是我们常说的 https。继续做~
2020 年 11 月 20 日 09:08
回复
没有更多评论了
发现更多内容

无代码平台,完成业务的最后一公里

钟杰

JAVA集合之LinkedList底层实现和原理

彭阿三

linkedlist

架构师训练营期末大作业

史慧君

三步带你开发一个短链接生成平台

Geek_Willie

JavaScript SpreadJS Node

数字货币管理,3 大新模式来了!

CECBC区块链专委会

区块链 数字货币

使用Grafana + simpod-json-datasource快速搭建数据看板

诸葛小猿

Grafana 数据可视化 simpod-json-datasource

甲方日常 22

大橘子

Vue 工作 随笔杂谈 日常

自己动手写SQL执行引擎

无毁的湖光

Java MySQL 数据库 Linux 算法

永续合约系统开发源码,区块链合约交易所搭建

WX13823153201

关于Java 编译Servlet或者自定义Tag,引入包的问题

谷鱼

Java web

这份阿里P8整理的Java学习资源,简直把所有Java知识操作都写出来了

Java成神之路

Java 编程 程序员 面试

朋友入职阿里请我吃饭,只因为面试前我逼他看了这些,经验很重要

小Q

Java 学习 架构 面试 程序员、

智能体:华为给时代炼一炉钢

脑极体

“哥伦布”华为,与智能联接新大陆

脑极体

让世界为之赞叹的开源项目,除了Linux,你知道Git吗?

小Q

Java git 学习 程序员 面试

高难度对话读书笔记—认知篇2

wo是一棵草

TensorFlow 篇 | TensorFlow 2.x 基于 Keras 模型的本地训练与评估

Alex

tensorflow 模型训练 keras

换道超车 区块链是你的捷径

CECBC区块链专委会

区块链 互联网

小朋友都能看懂的 HTTPS

Java架构师迁哥

巡展2020第十三届亚洲国际物联网展览会-南京站

InfoQ_caf7dbb9aa8a

上班路上也是一道美景

xcbeyond

生活 摄影 摄影征文

鼓励语言区块链技术的应用

CECBC区块链专委会

区块链

问世间异步为何物?

架构师修行之路

微服务 异步

不一样的面向对象(二)

书旅

php 面向对象

如何快速制造OOM

Since

JVM OOM

java安全编码指南之:可见性和原子性

程序那些事

Java java安全编码 java编码指南 java安全编码指南

Redis做分布式锁可能不那么简单

架构师修行之路

分布式 分布式锁

面试官:讲讲Redis的五大数据类型?如何使用?(内含完整测试源码)

冰河

redis Jedis JedisCluster

关于Java Servlet找不到自定义包或者第三方包

谷鱼

classes

程序执行太慢?快来学习SIMD加速技术,这个案例下的加速效果我也没想到(附带动手实验)

Optimize-Lab

go 优化代码 优化技巧 开源社区 simd

收藏+下载!Flink 社区最全学习渠道汇总

Apache Flink

flink

从HTTP到HTTP/3的发展简史-InfoQ