http 的发展历程

444 阅读9分钟

超文本传输协议 HTTP/0.9

主要用途

-- 学术用途的在网络中传输 html 超文本内容,所以被命名为超文本传输协议

工作流程

  • 建立 tcp 连接(tcp 连接的三次握手过程)
  • 发送 get 请求行信息
  • 服务器接收到请求信息,读取对应的 html 文件并以 ASCII 字节流返回给客户端
  • html 文档传输完毕断开 tcp 连接(tcp 四次挥手)


实现特点

  • 只有一个请求行,没有请求头和请求体
  • 服务器没有返回响应头信息,只需要返回 html 文档数据
  • 传输方式为 ASCII 字节流(ASCII 字节流是传输 html 文档的最佳传输方式)

超文本传输协议 HTTP/1.0

诞生原因

-- 1994年出现拨号上网服务、网景推出新款浏览器推动万维网高速发展,http/0.9 无法满足万维网的高速发展带来的核心需求。如:浏览器需要展示除 html 外的其他格式的文件(js、css、图片、音视频)等

http/1.0 的核心内容(支持多类型文件下载)

支持多文件下载需要解决的问题
  • 浏览器需要知道服务器返回的数据类型,然后针对性处理
  • 传输数据越来越大,需要采用服务器压缩数据的再传输方式来优化传输性能,浏览器需要知道服务器压缩数据的方式,然后进行解压缩
  • 万维网的全球性,需要服务器支持不同的语言,服务器需要浏览器告知需要展示什么类型的语言
  • 不同类型的文件数据编码方式可能不一致,浏览器需要知道文件的编码类型
accept: text/html accept-encoding: gzip, deflate, br accept-Charset: ISO-8859-1,utf-8 accept-language: zh-CN,zh

新特性

  • 引入请求头和响应头
  • 请求头中加入了 状态码 字段,通过响应行的方式来通知浏览器更新状态码
  • 引入 Cache 缓存机制,用来缓存已经下载过的数据
  • 在请求头中加入了 用户代理 字段,用来统计客户端数据


使用 http/1.0 存在的问题

  • 每次 http 通信都需要建立 tcp 连接、http 传输和 断开 tcp 连接三个阶段,在传输数据越来越大的情况下花费了过大的性能开销
  • 每个域名只能绑定唯一的 IP 地址,一个服务器只能支持一个域名
  • 需要在响应头设置完整的数据大小(Content-Length: 901)方便浏览器根据数据大小来接受数据。所以在传输动态数据时会导致浏览器不知道数据何时传输结束

超文本传输协议 HTTP/1.1


http/1.1 针对 http/1.0 出现的问题的解决方案

  • 增加持久连接(Connection:keep-alive\close),在一个 tcp 连接之上可以传输多个 http 请求,直到浏览器或者服务器明确要断开 tcp 连接为止(浏览器默认开启,对于同一域名,最多同时支持 6 个 tcp 持久连接,每个 tcp 连接同时只能发起一个 http 请求)
  • 提供虚拟主机的支持,在一台单独的物理服务器中绑定多个虚拟主机,这些主机共用同一 IP 地址。并且在请求头中增加 Host 字段告诉物理服务器,真正请求的是机子上的那个虚拟机中的服务
  • 通过引入 Chunk transfer 机制解决传输动态数据导致的问题,通过将数据分割传输,每个数据块的传输时附上上一次的数据块的长度(Content-Length: 0),如果为 0 时则表示传输完毕

http/1.1 做了哪些东西可以优化网络效率的?

  • 增加持久连接
  • 浏览器为每个域名最多同时维护 6 个 tcp 持久连接
  • 使用 CDN 实现的域名分片机制

使用 http/1.1 的主要的问题

-- 对带宽(每秒最大能发送 -- 上行带宽、接收 -- 下行带宽的字节数)的利用率不理想,造成这个问题的原因有:
  • 依旧是基于 tcp 实现,tcp 本身慢启动(tcp 采取的减少网络拥塞的策略)的特性
  • 同时开启多条 tcp 连接,竞争固定带宽,且 tcp 无法确定哪些需要优先下载的关键资源
  • 队头阻塞(在使用 tcp 持久连接时,多个 http 请求共用一个 tcp 连接管道,但是同一 tcp 连接管道中同时只能处理一个 http 请求,后续的需要排队等待管道队头的请求处理完毕)

超文本传输协议 HTTP/2

http/2 的实现思路

-- http/1.1 的核心问题是由 tcp 本身的特性(慢启动、多条 tcp 连接竞争带宽)和 http/1.1 持久连接机制产生的队头阻塞导致的,但是由于 http 仍然无法脱离 tcp 实现,所以整体实现思路是:
  • 使用同一域名单 tcp 连接来规避 tcp 的慢启动和多连接竞争带宽的问题
  • 使用多路复用机制实现资源的并行请求来解决 http/1.1 的 http 层级的队头阻塞问题(无法解决 tcp 数据包层级的队头阻塞)

http/2 的多路复用机制

什么是多路复用机制?
-- 客户端无论在何时都可以将 http 发送至服务器中,不需要排队等待其他的 http 请求完成返回后才能继续发送,服务器也可以随时返回相应资源的可以在客户端和服务器之间并行通信的机制


多路复用机制的实现
-- 在 http 和 tcp 层中间引入了二进制分帧层将 http 的请求数据拆分成带有 http 请求 ID 的多个 tcp 数据帧,服务器接收完所有该时刻同时发送的所有 http 请求的所有帧后(如何判断已经接收完了该 http 请求的所有帧),拼接 tcp 数据帧成一个完成的 http 请求,然后处理好响应数据,还是经过二进制分帧层处理响应数据成 tcp 数据帧返回给浏览器,浏览器返回的帧的请求 ID 编号提交到对应的请求中。具体的 http/2 请求流程为:
  • 浏览器发送请求数据(请求行、请求头、请求体)
  • 数据经过二进制分帧层处理,转换为一个个带有请求 ID 编号的 tcp 数据帧,通过协议栈将这些帧发送给服务器
  • 服务器接收到所有帧之后,会将所有相同 ID 的帧合并为一条完整的请求信息
  • 然后服务器处理该条请求,并将处理好的响应行、响应头和响应体分别发送至二进制分帧层
  • 二进制分帧层将响应数据转换为一个个带有请求 ID 编号的帧,经过协议栈发送给浏览器
  • 浏览器接收到响应帧根据 ID 编号将帧数据提交给对应的请求

http/2 其他特性

  • 可设置请求优先级
  • 服务器推送(将后续需要用到的数据提前推送到浏览器中,如请求 index.html 时,发现html 引用了几个其他文件,服务器附带将这些文件一起返回到浏览器中)
  • 对请求头和响应头压缩

如何部署使用 http/2 ?


使用 http/2 还存在的问题

  • tcp 层级的队头阻塞
-- http/2 的传输效率随着丢包率的增加而减低(经统计,丢包率超过 2% 时,http/2 表现不如 http/1.1),为什么呢?
    • http/2 中,一个域名的多个请求经过二进制分帧层处理的后的 n 多个 tcp 数据包共用一个 tcp 连接管道进行传输,如果任意一个 tcp 数据包丢失则会暂停该 tcp 管道,等待丢失的包重新传输,此时就会阻塞所有请求。
    • http/1.1 会为每个域名同时开启最多 6 个 tcp 连接,即使一个 tcp 阻塞了,也不至于阻塞其他请求
  • tcp 建立连接的延时
    • RTT(Round Trip Time)从浏览器发送一个数据包到服务器,再从服务器返回数据包到浏览器的整个往返时间
    • 建立 tcp 需要的 RTT 计算
      • tcp 三次握手,需要 1.5 次往返
      • tls 加密需要 1~2 次往返(tls1.2 和 1.3不同)
  • tcp 协议僵化
  • 操作系统的稳定特性。由于 tcp 是通过操作系统内核来实现,应用程序没有自由修改的权限,所以操作系统的稳定特性(更新会远远慢于应用程序)是导致 tcp 协议僵化的原因之一
  • 中间设备的僵化。网络传输中的传输设备(如:路由器、防火墙、NAT - 网络地址转换、交换机等)依赖于很少升级且使用了大量 tcp 特性的软件。且这些设备是只能用来传输tcp 和 udp 报文,如果更新 tcp 协议,则这些中间设备无法理解传输的数据导致被丢弃。很大程度上阻碍了 tcp 的更新。

超文本传输协议 HTTP/3

http/3 的实现思路

-- 使用基于 udp 修改的 quic 协议实现

为什么要采用 quic 协议,而不从修改 tcp 协议的思路入手?

-- 由于中间设备只理解 tcp 和 udp 数据包(中间设备僵化),故只能从其中二选一,加之操作系统导致 tcp 难以更新(操作系统的稳定性)的原因。http/3 选择了基于 udp 修改的 quic 协议来实现

quic 协议做了什么事情

  • 实现类 tcp 的流量控制、可靠传输功能
  • 集成 tls 加密功能(目前使用的 tcl1.3)
  • 实现 http/2 中的多路复用,但是这里的多路复用是有多个可以并发的独立数据流为每个请求开辟独立的传输通道,与 tcp 分帧在同一通道中传输有本质区别。解决了 http/2中的 tcp 层级的队头阻塞问题


  • 实现快速握手的功能。基于 udp 实现,避免了 tcp 的三次握手,可以更快速的建立传输连接

http/3 的主要挑战 - 推广难度大

  • 浏览器和服务器的支持程度低
  • 操作系统对 udp 的优化程度低
  • 中间设备对 udp 的优化程度低,导致丢包率高(据统计有 3% ~ 7%)