HTTP简介
本文从早期的HTTP/0.9出发,针对每次标准的更新分析其优缺点,层层递进,面面俱到,到如今的HTTP/3.0,使大家对HTTP的发展有比较全面的认识和理解。
HTTP协议全称(Hyper Text Transfer Protocol)超文本传输协议,是用于传输诸如 HTML 的超媒体文档的应用层协议。作为TCP五层模型的应用层,它被设计用于 Web 浏览器和 Web 服务器之间的通信,但它也可以用于其他目的。
HTTP是一个属于应用层、面向对象、无状态的协议。所谓无状态是指HTTP协议自身不对请求和响应之间的通信状态进行保存。用HTTP协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保存之前一切的请求和响应报文的信息。这是为了更快地处理大量的事务,确保协议的可伸缩性。当然为了解决这一问题,实现保持状态功能,引入了cookie技术对状态进行管理。
HTTP发展历史
HTTP协议版本大致可以细分为以下几个版本:
HTTP/0.9
- 主要功能:主要规定客户端和服务器的通信格式
- 缺点:服务器只能回应html格式的字符串,仅有一个get命令
HTTP/1.0
- 主要功能
- 任何格式的内容均可发送 (文字、图像、视频、二进制)
- 引入了POST、HEAD命令
- HTTP 请求和回应的格式也变了。除了数据部分,每次通信都必须包括头信息(HTTP header)
- 新增状态码、If-Modified-Since,Expires缓存机制
- 缺点:
- 无法复用链接,完成即断开,重新慢启动和 TCP 3次握手
- head of line blocking: 线头阻塞,导致请求之间互相影响
HTTP/1.1
- 主要功能
- 长链接:支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟,默认开启 Connection: keep-alive
- 管线化技术:管线化技术是在持久化连接的基础上,进一步对通信性能的提升。在持久化连接下,请求是顺次进行的。上次请求得到响应后,才能发送下次请求。管线化技术就是指能在未收到响应时,顺次发送多个响应。
- 增加host头域:请求消息和响应消息都支持Host头域,且请求消息中没有头域会报告一个错误(400 Bad Request),服务器应该接受以绝对路径标记的资源请求。
- 引入transfer-Encoding:chunked将发送方消息分割成若干个任意大小的数据块,每个数据块在发送时都附上块长度,最后用一个零长度的块作为消息结束标志;允许发送方只缓存消息的一个片段,避免缓存整个消息带来的过载。
- 缓存处理:引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
- 缺点
- 高延迟–带来页面加载速度的降低
- 无状态特性 – 带来巨大的HTTP头部
- 明文传输 – 带来的不安全性
- 不支持服务器推送消息
HTTP/2.0
谷歌在2009年设计的基于TCP的 SPDY 协议,主要解决 HTTP/1.1 效率不高的问题。 这个协议在 Chrome 浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。SPDY 可以说是综合了 HTTPS 和 HTTP 两者有点于一体的传输协议
- 主要功能
- 多路复用:优雅的采取了多路复用(multiplexing)。多路复用通过多个请求 stream 共享一个 tcp 连接的方式,解决了 HOL blocking 的问题,降低了延迟同时提高了带宽的利用率。
- 请求优先级:允许给每个 request 设置优先级,这样重要的请求就会优先得到响应
- header压缩:合适的压缩算法 HPACK可以减小包的大小和数量。
- 基于HTTPS的加密传输,提高数据传输的安全性。
- 支持服务端推送
- 缺点
- 本质是基于TCP的连接,TCP 以及 TCP+TLS建立连接的延时
- TCP的队头阻塞并没有彻底解决
- 在HTTP/2中,多个请求是跑在一个TCP管道中的。但当出现丢包时,HTTP/2 的表现反倒不如 HTTP/1 。
- 因TCP为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认。HTTP/2出现丢包时,整个 TCP 都要开始等待重传,那么就会阻塞该TCP连接中的所有请求。而对于HTTP/1.1来说,可开启多个 TCP 连接,出现这种情况反到只影响其中一个连接,剩余的TCP连接还可正常传输数据。
HTTP/3
HTTP/2解决了应用层面的队头阻塞问题,但只要还是基于TCP,就避免不了TCP的队头阻塞问题。而TCP在设计之初就是为了单链接而设计。HTTP/3基于UDP协议实现了类似于TCP的多路复用数据流、传输可靠性等功能,这套功能被称为QUIC协议。下个章节重点讲解QUIC。
呼之即出的QUIC
来源?主要针对的问题?
HTTP2的问题更多的是基于TCP存在的问题
- 对头阻塞没有彻底解决:TCP为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认。HTTP/2出现丢包时,整个 TCP 都要开始等待重传,那么就会阻塞该TCP连接中的所有请求。而HTTP/2只有一个连接,其他所有请求都会被阻塞。随着丢包率的增加,HTTP/2的传输效率也越来越差。
- TCP建立连接的延时:TCP建立连接时的三次握手,如果是HTTPS还有TLS连接握手,整体就需要3~4个RTT(TCP1.5个,TLS根据1.2/1.3版本会有不同的表现)
QUIC协议
QUIC(Quick UDP Internet Connections,快速 UDP 网络连接) 基于 UDP,正是看中了 UDP 的速度与效率。同时 QUIC 也整合了 TCP、TLS 和 HTTP/2 的优点,并加以优化。
QUIC 是用来替代 TCP、SSL/TLS 的传输层协议,在传输层之上还有应用层,我们熟知的应用层协议有 HTTP、FTP、IMAP 等,这些协议理论上都可以运行在 QUIC 之上,其中运行在 QUIC 之上的 HTTP 协议被称为 HTTP/3,这就是”HTTP over QUIC 即 HTTP/3“的含义。如下图:
零RTT建立连接
大家都知道HTTP/2连接基于TCP,而TCP建立连接时需要3个RTT,考虑到HTTPS还有TLS连接,如果TLS升级到1.3,也需要2个RTT,而 QUIC 采用了类似于 TCP Fast Open 的技术,如果之前连接过,那么之后可以不用重复握手而直接开始传送数据,以实现 0-RTT 往返时延。即便之前没有连接过,也可以在 1-RTT 内完成连接并开始传送数据。并且自身就拥有与 TLS 等效的加密措施。下图可以形象差、看出HTTP/2和HTTP/3建立连接的对比:
队头阻塞和多路复用
HTTP2的每个请求都被拆分为多个Frame通过一条TCP链接同时被传输,不同的请求的frame组合成一个stream,而stream是TCP上的逻辑传输单元,我们假设一种情况,在一个TCP同时传输4个stream,其中steam1安全到达,stream2的第3个frame丢失,因为TCP有严格的前后处理顺序,先发的frame先处理,这样就会等待发送方重新发送第3个frame,stream3和stream4虽然已经到达却不能被处理,这时整个连接阻塞。
所以队头阻塞会导致HTTP/2在容易丢包的网络环境里比HTTP/1.1更慢。
那QUIC的解决方式是什么呢?
- QUIC基于packet传输,整个加密、传输、解密的过程都是基于packet,避免队头阻塞
- QUIC基于UDP,UDP在接收端队数据的处理没有先后顺序,即使中间丢失包,也不会阻塞整个连接。
连接迁移
大家有时候可能会遇到这样的场景:当我们切换新的网络时,即使网络状态良好,但内容可能也需要加载很久,这是为什么呢?
大家都知道TCP连接基于四元组(源 IP、源端口、目的 IP、目的端口),当我们切换网络时至少会有一个因素发生变化,导致连接发生变化。当连接发生变化时,如果还使用原来的 TCP 连接,则会导致连接失败,就得等原来的连接超时后重新建立连接。所以当我们切换新网络时,检测到网络变化时立刻建立新的 TCP 连接,即使这样,建立新的连接还是需要几百毫秒的时间。
那么QUIC是怎么处理的呢?
QUIC 的连接不受四元组的影响,当这四个元素发生变化时,原连接依然维持。
QUIC 使用的死一个 64 位的随机数,这个随机数被称为 Connection ID,对应每个stream,即使 IP 或者端口发生变化,只要 Connection ID 没有变化,那么连接依然可以维持。
单调递增的报文序号
TCP通过字节序号和ACK来确认消息的有序到达,而QUIC是基于报文序号,并且报文序号单调递增。
那字节序号的问题是什么呢?
假设字节序号5的包,发送方在重传计时器超市之前没有收到接收方的确认,此时发送方重传字节序号5的包,然后这时在网络中有两个字节序号为5的包(假设第一个并没有丢失,只是慢而已)接收方可能收到第一个也有可能收到第二个包,无论收到哪个,接收方都会回复ACK6给发送方表示字节序号5已经收到。但对于发生方,单从ACK6无法判断接收方接受的是哪个包,导致RTT的计算有误差,此时RTT是按照第一个包发出的时间计算还是按照第二个重传的包发出的时间计算?这就是所谓的TCP重传歧义。
QUIC的解决方式?
采用报文序号不会有重传歧义的问题,假设报文2重传了,重传的序号递增为3,接收方ACK2说明收到了初传报文2,ACK3说明收到重传报文3,对于两者来说他们的offset域是一样的也就是同一块数据,这样就解决了重传歧义的问题。保证RTT的准确计算。
总结
QUIC丢掉之前HTTP对于TCP、TLS的包袱,基于新的UDP,并且对于TCP、TLS、HTTP/2的优缺点进行改进,实现了一个安全高效可靠的HTTP通信协议。但是QUIC本身基于UDP没有队头阻塞的特性,而这些特性在多路复用的场景在弱网环境下队业务均有较好的性能提升和卡顿率降低。所以在这方面的特性还需要充分挖掘。
在HTTP协议发展的20多年来,每次标准的更新都会带来一大批的服务器和浏览器厂商升级以及业务的提升。对于一名合格的开发者而言,只有不断的摸索和跟进这些新技术,才能做到不被趋势所淘汰。