一文看完HTTP3的演化历程(149)

发布于2019-04-21 20:41:41

HTTP协议为Web的发展提供了驱动力,它始于1991年的HTTP/0.9,在1999年演变为HTTP/1.1,并由IETF(互联网工程任务组)负责进行标准化。HTTP/1.1存在了很长一段时间,但Web不断变化的需求要求推出更好的协议,于是HTTP/2在2015年出现了。IETF最近宣布要推出新的版本,即HTTP/3。对于有些人来说,这是一个惊喜,但也会让他们感到有一点点困惑。如果你没有密切关注IETF的工作,就会觉得HTTP/3出现得很突然。不过,我们可以通过一系列实验和Web协议的演变史来追溯它的起源,特别是QUIC传输协议。

如果你还不熟悉QUIC,可以先看看我的一些同事所写的文章。John的这篇文章描述了当今HTTP世界的一些恼人之处,Alessandro的这篇文章描述了传输层的实际细节,而Nick的这篇文章介绍了如何进行测试。我们在https://cloudflare-quic.com收集了更多的资源。如果你喜欢,请务必看一看我们用Rust实现的QUIC协议quiche

HTTP/3是HTTP应用程序到QUIC传输层的映射。这个名称在第17版草案(draft-ietf-quic-http-17)中正式启用,该草案于2018年10月底提出,在11月于曼谷举行的IETF 103大会期间进行了讨论并达成初步的共识。HTTP/3之前叫作HTTP over QUIC,再往前又叫HTTP/2 over QUIC。在那之前,我们有HTTP/2 over gQUIC,再往前,我们有SPDY over gQUIC。事实上,HTTP/3只是一种基于QUIC(基于UDP的多路复用和安全传输)的HTTP新语法。

在这篇文章中,我们将探讨HTTP/3旧名称背后的历史以及改名背后的动机。我们将回到HTTP的早期阶段,介绍一路走来所做的工作。如果你想要获得一个整体的视图,可以打开这个非常详细的SVG版本


HTTP/3协议层

场景设定

在开始介绍HTTP之前,需要注意的是,有两个协议都使用了QUIC这个名称。gQUIC通常用来表示谷歌QUIC(原始协议),而QUIC通常用来表示IETF正在进行标准化的版本。

从90年代初期开始,Web的需求已经发生了很大的变化。我们有了新版本的HTTP,并增加了传输层安全(TLS)来增强安全性。

为了更好地解释HTTP和TLS的历史,我整理了协议规范和日期的细节。这些信息通常以文本形式呈现出来,例如按日期排序的项目列表。但因为存在标准分支,它们在时间上有所重叠,简单的列表无法表达出这种复杂的关系。而且,在HTTP方面还存在一些并行的工作,这些工作通过重构核心协议来简化使用,通过扩展协议来增加新的用途,以及通过重新定义数据交换方式来提高性能。要想跨越近30年的互联网发展史和不同的工作流分支,并把它们串起来,需要对它们进行可视化。于是,我制作了Cloudflare Secure Web Timeline。

接下来,我将按照这个时间表来解释HTTP历史的关键篇章。为了更好地理解本文的内容,最好先知道为什么要进行协议标准化以及IETF是如何实现的。因此,在回到时间表之前,我们先简要介绍这个主题。如果你已经很熟悉IETF,可以跳过下面的部分。

互联网标准的类型

通常,标准定义了共同的引用术语、范围、约束、适用性和其他考虑事项。标准可以以多种形式存在,可以是非正式的(也就是所谓的“事实上的标准”)或正式的(由标准定义组织——例如IETF、ISO或MPEG——同意或发布)。标准被用在很多领域,甚至连茶叶都有一个正式的标准——英国制茶标准BS 6008。

早期Web使用的是在IETF外部发布的HTTP和SSL协议,这些在Secure Web Timeline上被标记为红线。客户端和服务器对这些协议的采用使它们成为事实上的标准。

到了某个时刻,人们决定将这些协议正式化(后面部分将描述其背后的动机)。互联网标准通常由IETF负责定义,IETF的指导原则是“粗略共识和可运行的代码”。这个原则以互联网的开发和部署经验为基础,与尝试在真空中开发完美方案的“clean room”方法是不一样的。

IETF互联网标准被称为RFC。这个解释起来很复杂,所以我建议你阅读由QUIC工作组联合主席Mark Nottingham撰写的博文“如何阅读RFC”。这里所谓的工作组(或WG)一般是指邮件列表。

IETF每年都会召开三次会议,为所有工作组提供时间和设施,如果他们愿意,可以亲自参加会议。会议期间的议程可能安排得非常紧凑,只有非常有限的时间可用于深入讨论技术领域的问题。为了解决这个问题,一些工作组还选择在IETF常规会议中间的几个月召开临时会议。自2017年以来,QUIC工作组已经召开了几次临时会议,会议主页上提供了完整的会议清单

IETF会议还为其他与IETF相关的人员提供了会面的机会,例如互联网架构委员会(Internet Architecture Board)或互联网研究工作组(Internet Research Task Force)。近年来,在IETF会议之前的周末都会举行IETF Hackathon。这为社区提供了开发可运行代码的机会,更重要的是,可以与其他人在同一个房间里进行互操作性测试,这样有助于找出规范中存在的问题。

本文要强调的一点是,RFC不是突然间出现的,它们一般会经历一个过程,通常从IETF互联网草案(I-D)开始。如果规范已经存在,那么要准备一个I-D就很简单,只需要进行简单的重新格式化。I-D从发布之日起有6个月的有效期。要保持I-D的活跃状态,就要发布新版本。在实际当中,一个I-D的消失并不会产生多大后果,而且这种事情经常发生。这些文件会继续托管在IETF文档网站上,任何想要阅读它们的人都可以继续访问它们。

I-D在Secure Web Timeline中使用紫色线条表示。每条线都有一个唯一的名称,格式为draft-{作者姓名}-{工作组}-{主题}-{版本}。工作组字段是可选的,有时会发生变化。如果一个I-D被IETF采纳,或者直接由IETF内部发起,名字则为draft-ietf-{工作组}-{主题}-{版本}。I-D可能会有分支,会发生合并,或者分支直接停止发展。版本从00开始,每次发布新草案时增加1。例如,I-D第4稿的版本为03。如果I-D名称发生变化,版本将重置为00。

需要注意的是,任何人都可以向IETF提交I-D,但你不应该把它们当作标准来看待。如果IETF的标准化流程针对某个I-D达成了共识,并且最终文档通过了评审,我们最终会得到一个RFC。在这个阶段名称会再次发生变化。每个RFC都会获得一个唯一的编号,例如RFC 7230。这些在Secure Web Timeline上使用蓝线表示。

RFC是不可变文档,这意味着修改RFC后需要一个全新的编号。修改RFC可能是为了合并勘误(编辑方面或技术方面的错误)或为了改进规范的布局。RFC可能会淘汰旧版本(完全替换),或者更新它们(实质性变更)。

所有IETF文档均可在http://tools.ietf.org上公开获得。我个人认为IETF Datatracker对用户更加友好,因为它提供了文档的进度可视化。

下面是一个例子,显示了RFC 1945(HTTP/1.0)的开发过程,很显然,它是Secure Web Timeline的灵感来源。

有趣的是,在我创建Secure Web Timeline的过程中,我发现上面的可视化其实是不对的。由于某种原因,它缺少了draft-ietf-http-v10-spec-05。由于I-D的生命周期是6个月,因此在成为RFC之前似乎存在一个空白,实际上,草案05在1996年8月之前仍然有效。

Secure Web Timeline

在稍微了解了互联网标准文档的实现方式之后,现在可以开始介绍Secure Web Timeline了。接下来将展示一些图表,它们显示了整个时间表的重要部分。每个点代表文档或功能的可用日期。对于IETF文档,为清晰起见,省略了草案编号。如果你想查看所有详细信息,请参看完整的时间表

HTTP从1991年的HTTP/0.9协议开始,在1994年发布了draft-fielding-http-spec-00,这个I-D很快被IETF采用,改名为draft-ietf-http-v10-spec-00。这个I-D在1996年成为RFC 1945(HTTP/1.0)之前经历了6个草案版本。

但是,在HTTP/1.0相关工作完成之前,另一项与HTTP/1.1相关的工作就已启动。draft-ietf-http-v11-spec-00于1995年11月发布,并于1997年正式作为RFC 2068。你们可能已经发现Secure Web Timeline中并未完全捕获这一系列事件,这是可视化工具的问题。

1997年中期,HTTP/1.1的修订工作启动了,对应的I-D为draft-ietf-http-v11-spec-rev-00。这项工作于1999年完成,并作为RFC 2616发布。2007年之前,IETF的HTTP世界都很平静。

SSL和TLS简史

SSL 2.0规范在1995年左右发布,而SSL 3.0则在1996年11月发布。有趣的是,SSL 3.0对应的RFC 6101于2011年8月发布。根据IETF的说法,这属于“Historic”,即“通常是为了记录那些被考虑过但又被放弃的想法,或者在决定记录它们时就已经是Historic的协议”。对于这种情况,拥有一个描述SSL 3.0的IETF文档是有好处的,因为它可以作为规范在其他地方被引用。

我们更感兴趣的是SSL是如何激发了TLS的开发,TLS从1996年11月开始,I-D为draft-ietf-tls-protocol-00。它经历了6个草案版本,并在1999年初作为RFC 2246(TLS 1.0)发布。

在1995年到1999年期间,SSL和TLS协议被用于保护HTTP通信。作为一种事实上的标准,这种方式运作得很好。直到1998年1月,随着draft-ietf-tls-https-00的发布,HTTPS的正式标准化过程才开始。这项工作在2000年5月结束,发布了RFC 2616(HTTP over TLS)。

TLS在2000年至2007年期间继续演化,出现了TLS 1.1和TLS 1.2。TLS的下一个版本于2014年4月被采用,即draft-ietf-tls-tls13-00。在经历了28个草案之后,于2018年8月成为RFC 8446(TLS 1.3)。

互联网标准化进程

我希望你能够通过仔细观察时间表了解IETF的工作原理。互联网标准的形成大致是这样的:研究人员或工程师设计适合特定用例的实验性协议,然后在不同规模水平公开或私下对协议进行实验。实验数据有助于识别或改进问题。相关工作可能被公开,用于向公众作出解释,收集更广泛的意见,或找到其他实现者。那些采用了早期工作成果的人让实验协议成为了事实上的标准,对实验协议成为正式标准起到了促进作用。

对于正在考虑实现、部署或以某种方式使用协议的组织而言,协议的状态是一个重要的考虑因素。正式的标准化过程会让事实上的标准更具吸引力,因为它会带来更高的稳定性。但需要注意的是,并非所有正式标准化都能获得成功。

确定最终标准的过程几乎与标准本身一样重要。以最初的想法为基础,邀请人们一起来贡献想法,这些人拥有更广泛知识和经验,可以为更广泛的人群带来更有用的东西。但是,标准化过程并不总是那么容易,陷阱和障碍总是存在的。有时候,这个过程需要很长时间,以至于最终得到的结果已经变得不那么重要了。

Cloudflare的可运行代码

Cloudflare很自豪能够成为不断发展的新协议的早期采用者。我们很早就开始采用新标准,如HTTP/2,我们还尝试使用实验性或尚未最终确定的功能,如TLS 1.3和SPDY。

在IETF标准化过程中,将可运行的代码部署在跨不同网站的真实网络上可以帮助我们了解协议在真实环境中的运行情况。我们将现有的专业知识和从实验中获得的信息结合起来,用以改进可运行的代码,并向正在标准化协议的工作组反馈有意义的问题和改进意见。

测试新的东西并不是唯一的优先事项。创新者应该知道什么时候该前进,什么时候该把旧的创新抛在脑后。有时候这与面向安全的协议有关,例如,由于POODLE漏洞,Cloudflare默认禁用了SSLv3。在其他情况下,旧协议会被更先进的新协议所取代,Cloudflare就使用HTTP/2替换了SPDY。

相关协议的引入和弃用在Secure Web Timeline上使用橙色线表示。虚线竖线有助于将Cloudflare事件与相关的IETF文档关联起来。例如,Cloudflare在2016年9月引入了TLS 1.3支持,而RFC 8446最终版在两年后的2018年8月发布。

HTTP重构

HTTP/1.1是一个非常成功的协议。时间表显示,在1999年之后,IETF就没有太多的动作。然而,真实的情况是,多年的使用经验发现了RFC 2616中潜在的问题,这些问题导致了一些互操作性问题。此外,其他RFC(如2817和2818)扩展了RFC 2616。2007年,IETF决定启动一项新工作,以改进HTTP协议规范。这项工作被称为HTTPbis(“bis”源于拉丁语,意为“两个”、“两次”或“重复”),并成立了新的工作组。原始章程描述了他们试图解决的问题。

简单地说就是HTTPbis决定重构RFC 2616。它将合并勘误修复,并借鉴在此期间发布的其他一些规范的某些方面。他们将文档分成了几个部分,于2007年12月发布了6个I-D:

上图显示了在最终标准化之前,这项工作如何通过长达7年的起草过程,发布了27个草案版本。2014年6月,发布了所谓的RFC 723x系列(其中x的范围为从0到5)。HTTPbis工作组主席用“RFC2616已死”来庆祝这一成就,也就是说这些新文件将使旧的RFC 2616作废。

这与HTTP/3有什么关系?

当IETF正忙于RFC 723x系列时,这个世界并没有停下发展的脚步。人们继续在互联网上增强、扩展和试验HTTP。其中就包括谷歌,谷歌已经开始试验一种叫作SPDY(发音为speedy)的协议。谷歌宣称,这个协议旨在提高Web浏览的性能。2009年底,SPDY v1发布,很快又在2010年推出SPDY v2。

我不打算深入解释SPDY的技术细节,关键的是要知道,SPDY采用了HTTP的核心范式,并对数据交换格式稍作修改。事后看来,HTTP明确划分了语义和语法。语义描述了请求和响应交换的概念,包括:方法、状态码、标头(元数据)和正文(有效载荷),语法则描述了如何将语义映射到在网络上传输的字节。

HTTP/0.9、1.0和1.1共享了很多语义,还以字符串形式共享了一些语法。SPDY采用了HTTP/1.1语义,并将语法从字符串改为二进制形式。

谷歌的SPDY实验表明,他们想要改变HTTP语法,但会保留现有的HTTP语义。例如,保留https://格式的URL可以避免很多可能会影响到采用率的问题

在看到了一些积极的结果后,IETF认为是时候看看HTTP/2.0的效果了。于2012年3月举行的IETF 83大会的一份幻灯片展示了HTTP/2.0的需求、目标和成功的衡量标准。它还明确指出“HTTP/2.0只在传输格式方面与HTTP/1.x不兼容”。

在那次会议期间,社区成员被邀请分享他们的提案。提交审议的I-D包括draft-mbelshe-httpbis-spdy-00、draft-montenegro-httpbis-speed-mobility-00和draft-tarreau-httpbis-network-friendly-00。最终,SPDY草案获得通过,并于2012年11月启动draft-ietf-httpbis-http2-00相关工作。在短短两年多的时间内完成了18次草案,并于2015年发布了RFC 7540(HTTP/2)。在这期间,HTTP/2的语法分散到足以使HTTP/2和SPDY不兼容。

这些年,IETF一直忙于与HTTP相关的工作,HTTP/1.1重构和HTTP/2标准化同时进行。这与21世纪初多年的平静形成鲜明对比。

尽管HTTP/2正处于标准化阶段,但使用SPDY和试验SPDY仍然是有好处的。Cloudflare从2012年8月起开始支持SPDY,但在2018年2月就弃用了。当时的统计数据显示,不到4%的Web客户想要使用SPDY。2015年12月,我们又推出了HTTP/2支持,也就是在RFC发布后不久,我们的数据分析表明,有相当一部分Web客户端可以使用它。

支持SPDY和HTTP/2协议的Web客户端倾向于使用TLS。2014年9月推出的通用SSL可以确保所有注册到Cloudflare的网站都能够在我们引入这些新协议时使用它们。

gQUIC

谷歌在2012年至2015年期间继续进行实验,并发布了SPDY v3和v3.1。他们也开始研究gQUIC(当时发音为quick),并于2012年初推出初始版本的规范。

gQUIC的早期版本使用了SPDY v3形式的HTTP语法,因为当时HTTP/2规范还没有完成。SPDY二进制语法被打包成可以在UDP数据报中发送的Q​​UIC数据包,与HTTP使用的TCP传输有所不同。


SPDY over gQUIC协议层

gQUIC使用了一些巧妙的技巧来提升性能,其中之一就是打破应用程序和传输之间的分层界限。这意味着gQUIC只支持HTTP。因此,当时被称为“QUIC”的gQUIC被当作HTTP的下一个候选版本。尽管QUIC在过去几年中不断发生变化,直到今天,人们还是将QUIC理解为最初的HTTP变体。

有关gQUIC的实验继续进行,并最终切换到更接近HTTP/2的语法,以至于大多数人直接将其称为“HTTP/2 over QUIC”。但是,由于技术方面的限制,它们之间存在一些非常微妙的差异,比如HTTP标头的序列化和交互方式。虽然这是一个很小的差异,但却意味着HTTP/2 over gQUIC与IETF的HTTP/2是不兼容的。

最后,我们始终需要考虑互联网协议的安全性问题。gQUIC没有使用TLS,相反,谷歌开发了一种叫作QUIC Crypto的方法,可以加快安全握手过程。已经与服务器建立了安全会话的客户端可以重用会话信息来执行“零往返时间”或0-RTT握手(0-RTT后来被TLS 1.3采用)。

那么HTTP/3到底是什么?

到目前为止,我们应该已经熟悉了标准化过程,也知道了gQUIC是什么。2015年6月,谷歌提交了题为“QUIC: A UDP-based Secure and Reliable Transport for HTTP/2”的draft-tsvwg-quic-protocol-00。它的语法几乎与HTTP/2相同。

简单地说,与IETF合作的结果就是,QUIC在传输层似乎提供了很多优势,应该与HTTP解耦,因此有必要重新引入分层。此外,有人倾向于返回到基于TLS的握手机制(由于在这个时候有关TLS 1.3的工作正在进行中,同时也正在整合0-RTT,所以并没有那么糟糕)。

大约一年后,也就是在2016年,提交了一系列新的I-D:

这是另一个HTTP和QUIC令人感到混淆的地方。draft-shade-quic-http2-mapping-00的标题是“HTTP/2 Semantics Using The QUIC Transport Protocol”,并将自己描述为“基于QUIC的HTTP/2语义映射”。但其实这种说法不是很恰当。HTTP/2在保持语义的同时也在改变语法。此外,“HTTP/2 over gQUIC”已经不能用来准确地描述语法了,至于原因,之前已经提到过了。

IETF版本的QUIC是一个全新的传输协议。这是一个巨大的承诺,在做出这个承诺之前,IETF希望先看看成员的实际兴趣。为此,2016年在柏林举行的IETF 96大会上召开了正式的“Birds of a Feather”会议。我很幸运能够亲自参加这次会议,还有其他数百人也参加了会议。在会议结束时达成了共识,QUIC将被IETF采用并标准化。

用于将HTTP映射到QUIC的第一个IETF QUIC I-D(draft-ietf-quic-http-00)采用了Ronseal方法,并将其名称简化为“HTTP over QUIC”。不幸的是,这项工作并没有完全完成,而且在正文中出现了很多次“HTTP/2”。I-D新编辑Mike Bishop发现了这一点,并开始修复HTTP/2的命名错误。在01草案中,描述被改为“基于QUIC的HTTP语义映射”。

随着时间的推移和版本的增加,“HTTP/2”一词的使用在逐渐减少。往后推两年,也就是在2018年10月,I-D到了第16版。虽然HTTP over QUIC与HTTP/2很相似,但它终究是一个独立的、不向后兼容的HTTP语法。对于那些没有密切关注IETF开发的人(占了大多数)来说,文档名称并没有体现出这种差异。标准化的要点之一是促进交流和互操作性,然而,像命名这样简单的事情是造成社区混乱的主要原因。

回想一下2012年所说的“HTTP/2.0只在传输格式方面与HTTP/1.x不兼容”。IETF遵循了现有的线索。在IETF 103召开之前和召开期间,经过深思熟虑,各方一致同意将“HTTP over QUIC”重命名为HTTP/3。

但RFC 7230和7231不同意你对语义和语法的定义!

有时候,文档的标题也会令人感到混淆。描述语法和语义的HTTP文档是:

我们可能会对这些名称进行过多的解读,认为基本的HTTP语义是特定于HTTP版本的,即HTTP/1.1。好在HTTPbis工作组正在努力解决这个问题。一些成员正在进行另一轮文件修订工作。这项工作现在正在进行当中,被称为HTTP核心活动。它将把六份草案压缩成三份:

基于这种新的结构,HTTP/2和HTTP/3成为了通用HTTP语义的语法定义。这并不意味着它们除了语法之外就没有自己的特性,但这应该有助于今后的讨论。

总结

这篇文章简要介绍了HTTP在过去三十年的标准化过程。我试着在不涉及很多技术细节的情况下解释我们是如何发展到达今天的HTTP/3的。如果你想要跳过中间的部分,希望用一句话来概括,那么应该是这样:HTTP/3只是一种基于IETF QUIC(一种基于UDP的多路复用和安全传输)的新HTTP语法。

在这篇文章中,我们介绍了HTTP和TLS发展过程的重要篇章。我们将全部内容整合到下面的这张Secure Web Timeline中。对于喜欢一探究竟的人,请务必查看完整版本,其中包含了草案编号。

英文原文:https://blog.cloudflare.com/http-3-from-root-to-tip/