一文读懂 HTTP/1HTTP/2HTTP/3

Posted 腾讯技术工程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文读懂 HTTP/1HTTP/2HTTP/3相关的知识,希望对你有一定的参考价值。




作者:charryhuang,腾讯 CSIG 前端开发工程师

从 1989 年万维网(www)诞生,HTTP(HyperText Transfer Protocol)经历了众多版本迭代,WebSocket 也在期间萌芽。1991 年 HTTP0.9 被发明。1996 年出现了 HTTP1.0。2015 年 HTTP2 正式发布。2020 年 HTTP3 或能正式使用。以下将会简单介绍。


HTTP1.1 与 HTTP2HTTP1.1 的缺陷
  1. 高延迟 — 队头阻塞(Head-Of-Line Blocking)

  2. 无状态特性 — 阻碍交互

  3. 明文传输 — 不安全性

  4. 不支持服务端推送

队头阻塞

队头阻塞是指当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。

针对队头阻塞:

1.将同一页面的资源分散到不同域名下,提升连接上限。虽然能公用一个 TCP 管道,但是在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态。

2.减少请求数量

3.内联一些资源:css、base64 图片等

4.合并小文件减少资源数

无状态特性

无状态是指协议对于连接状态没有记忆能力。纯净的 HTTP 是没有 cookie 等机制的,每一个连接都是一个新的连接。上一次请求验证了用户名密码,而下一次请求服务器并不知道它与上一条请求有何关联,换句话说就是掉登录态

不安全性

传输内容没有加密,中途可能被篡改和劫持。

SPDY 协议

SPDY 是由 google 推行的改进版本的 HTTP1.1 (那时候还没有 HTTP2)。

特性:

  1. 多路复用 — 解决队头阻塞

  2. 头部压缩 — 解决巨大的 HTTP 头部

  3. 请求优先级 — 先获取重要数据

  4. 服务端推送 — 填补空缺

  5. 提高安全性


多路复用

SPDY 允许在一个连接上无限制并发流。因为请求在一个通道上,TCP 效率更高(参考 TCP 拥塞控制 中的慢启动)。更少的网络连接,发出更密集的包。

头部压缩

使用专门的 HPACK 算法,每次请求和响应只发送差异头部,一般可以达到 50% ~90% 的高压缩率。

请求优先级

虽然无限的并发流解决了队头阻塞的问题,但如果带宽受限,客户端可能会因防止堵塞通道而阻止请求。在网络通道被非关键资源堵塞时,高优先级的请求会被优先处理。

服务端推送

服务端推送(ServerPush),可以让服务端主动把资源文件推送给客户端。当然客户端也有权利选择是否接收。

提高安全性

支持使用 HTTPS 进行加密传输。


HTTP2

HTTP2 基于 SPDY,专注于性能,最大的一个目标是在用户和网站间只用一个连接。

新增特性:

  1. 二进制分帧 - HTTP2 性能增强的核心

  2. 多路复用 - 解决串行的文件传输和连接数过多

二进制分帧

首先,HTTP2 没有改变 HTTP1 的语义,只是在应用层使用二进制分帧方式传输。因此,也引入了新的通信单位:帧、消息、流

分帧有什么好处?服务器单位时间接收到的请求数变多,可以提高并发数。最重要的是,为多路复用提供了底层支持。

多路复用

一个域名对应一个连接,一个流代表了一个完整的请求-响应过程。是最小的数据单位,每个会标识出该帧属于哪个也就是多个帧组成的数据流。多路复用,就是在一个 TCP 连接中可以存在多个流。演示


HTTP2 的缺陷
  1. TCP 以及 TCP+TLS 建立连接的延时

  2. TCP 的队头阻塞并没有彻底解决

  3. 多路复用导致服务器压力上升

  4. 多路复用容易 Timeout


建连延时

TCP 连接需要和服务器进行三次握手,即消耗完 1.5 个 RTT 之后才能进行数据传输。

TLS 连接有两个版本—— TLS1.2 和 TLS1.3,每个版本建立连接所花的时间不同,大致需要 1~2 个 RTT。

RTT(Round-Trip Time):往返时延。表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。

队头阻塞没有彻底解决

TCP 为了保证可靠传输,有一个“超时重传”机制,丢失的包必须等待重传确认。HTTP2 出现丢包时,整个 TCP 都要等待重传,那么就会阻塞该 TCP 连接中的所有请求。

RTO:英文全称是 Retransmission TimeOut,即重传超时时间;RTO 是一个动态值,会根据网络的改变而改变。RTO 是根据给定连接的往返时间 RTT 计算出来的。接收方返回的 ack 是希望收到的下一组包的序列号。

多路复用导致服务器压力上升

多路复用没有限制同时请求数。请求的平均数量与往常相同,但实际会有许多请求的短暂爆发,导致瞬时 QPS 暴增。

多路复用容易 Timeout

大批量的请求同时发送,由于 HTTP2 连接内存在多个并行的流,而网络带宽和服务器资源有限,每个流的资源会被稀释,虽然它们开始时间相差更短,但却都可能超时。

即使是使用 nginx 这样的负载均衡器,想正确进行节流也可能很棘手。其次,就算你向应用程序引入或调整排队机制,但一次能处理的连接也是有限的。如果对请求进行排队,还要注意在响应超时后丢弃请求,以避免浪费不必要的资源。引用


QUIC简介

Google
在推 SPDY 的时候就已经意识到了这些问题,于是就另起炉灶搞了一个基于 UDP 协议的 QUIC 协议。而这个就是 HTTP3。它真正“完美”地解决了“队头阻塞”问题。

主要特点
  1. 改进的拥塞控制、可靠传输

  2. 快速握手

  3. 集成了 TLS 1.3 加密

  4. 多路复用

  5. 连接迁移

改进的拥塞控制、可靠传输

从拥塞算法和可靠传输本身来看,QUIC 只是按照 TCP 协议重新实现了一遍,那么 QUIC 协议到底改进在哪些方面呢?主要有如下几点:

1. 可插拔 — 应用程序层面就能实现不同的拥塞控制算法。

一个应用程序的不同连接也能支持配置不同的拥塞控制。应用程序不需要停机和升级就能实现拥塞控制的变更,可以针对不同业务,不同网络制式,甚至不同的 RTT,使用不同的拥塞控制算法。

关于应用层的可插拔拥塞控制模拟,可以对 socket 上的流为对象进行实验。

2. 单调递增的 Packet Number — 使用 Packet Number 代替了 TCP 的 seq。

每个 Packet Number 都严格递增,也就是说就算 Packet N 丢失了,重传的 Packet N 的 Packet Number 已经不是 N,而是一个比 N 大的值。而 TCP 重传策略存在二义性,比如客户端发送了一个请求,一个 RTO 后发起重传,而实际上服务器收到了第一次请求,并且响应已经在路上了,当客户端收到响应后,得出的 RTT 将会比真实 RTT 要小。当 Packet N 唯一之后,就可以计算出正确的 RTT。

3. 不允许 Reneging — 一个 Packet 只要被 Ack,就认为它一定被正确接收。

Reneging 的意思是,接收方有权把已经报给发送端 SACK(Selective Acknowledgment) 里的数据给丢了(如接收窗口不够而丢弃乱序的包)。

QUIC 中的 ACK 包含了与 TCP 中 SACK 等价的信息,但 QUIC 不允许任何(包括被确认接受的)数据包被丢弃。这样不仅可以简化发送端与接收端的实现难度,还可以减少发送端的内存压力。

4. 前向纠错(FEC)

早期的 QUIC 版本存在一个丢包恢复机制,但后来由于增加带宽消耗和效果一般而废弃。FEC 中,QUIC 数据帧的数据混合原始数据和冗余数据,来确保无论到达接收端的 n 次传输内容是什么,接收端都能够恢复所有 n 个原始数据包。FEC 的实质就是异或。示意图:

5. 更多的 Ack 块和增加 Ack Delay 时间。

QUIC 可以同时提供 256 个 Ack Block,因此在重排序时,QUIC 相对于 TCP(使用 SACK)更有弹性,这也使得在重排序丢失出现时,QUIC 可以在网络上保留更多的在途字节。在丢包率比较高的网络下,可以提升网络的恢复速度,减少重传量。

TCP 的 Timestamp 选项存在一个问题:发送方在发送报文时设置发送时间戳,接收方在确认该报文段时把时间戳字段值复制到确认报文时间戳,但是没有计算接收端接收到包到发送 Ack 的时间。这个时间可以简称为 Ack Delay,会导致 RTT 计算误差。现在就是把这个东西加进去计算 RTT 了。

6. 基于 stream 和 connection 级别的流量控制。

为什么需要两类流量控制呢?主要是因为 QUIC 支持多路复用。Stream 可以认为就是一条 HTTP 请求。Connection 可以类比一条 TCP 连接。多路复用意味着在一条 Connetion 上会同时存在多条 Stream。

QUIC 接收者会通告每个流中最多想要接收到的数据的绝对字节偏移。随着数据在特定流中的发送,接收和传送,接收者发送 WINDOW_UPDATE 帧,该帧增加该流的通告偏移量限制,允许对端在该流上发送更多的数据。

除了每个流的流控制外,QUIC 还实现连接级的流控制,以限制 QUIC 接收者愿意为连接分配的总缓冲区。连接的流控制工作方式与流的流控制一样,但传送的字节和最大的接收偏移是所有流的总和。

最重要的是,我们可以在内存不足或者上游处理性能出现问题时,通过流量控制来限制传输速率,保障服务可用性。


快速握手

由于 QUIC 是基于 UDP 的,所以 QUIC 可以实现 0-RTT 或者 1-RTT 来建立连接,可以大大提升首次打开页面的速度。

集成了 TLS 1.3 加密

TLS 1.3 支持 3 种基本密钥交换模式:

(EC)DHE (基于有限域或椭圆曲线的 Diffie-Hellman)
PSK - only
PSK with (EC)DHE

在完全握手情况下,需要 1-RTT 建立连接。TLS1.3 恢复会话可以直接发送加密后的应用数据,不需要额外的 TLS 握手,也就是 0-RTT。

TLS 1.3 0-RTT 简单原理示意(基于 DHE):

但是 TLS1.3 也并不完美。TLS 1.3 的 0-RTT 无法保证前向安全性(Forward secrecy)。简单讲就是,如果当攻击者通过某种手段获取到了 Session Ticket Key,那么该攻击者可以解密以前的加密数据。

要缓解该问题可以通过设置使得与 Session Ticket Key 相关的 DH 静态参数在短时间内过期(一般几个小时)。


多路复用

QUIC 是为多路复用从头设计的,携带个别流的的数据的包丢失时,通常只影响该流。QUIC 连接上的多个 stream 之间并没有依赖,也不会有底层协议限制。假如 stream2 丢了一个包,也只会影响 stream2 的处理。

连接迁移

TCP 是按照 4 要素(客户端 IP、端口, 服务器 IP、端口)确定一个连接的。而 QUIC 则是让客户端生成一个 Connection ID (64 位)来区别不同连接。只要 Connection ID 不变,连接就不需要重新建立,即便是客户端的网络发生变化。由于迁移客户端继续使用相同的会话密钥来加密和解密数据包,QUIC 还提供了迁移客户端的自动加密验证。


挑战NAT 问题

NAT 概念

为了解决 IP 地址不足的问题,NAT 给一个局域网络只分配一个 IP 地址,这个网络内的主机,则分配私有地址,这些私有地址对外是不可见的,他们对外的通信都要借助那个唯一分配的 IP 地址。所有离开本地网络去往 Internet 的数据报的源 IP 地址需替换为相同的 NAT,区别仅在于端口号不同。

原因

TCP 和 UDP 的报文头部不同导致 NAT 问题的出现。

NAT 设备的端口记忆问题

对于基于 TCP 的 HTTP、HTTPS 传输,NAT 设备可以根据 TCP 报文头的 SYN/FIN 状态位,知道通信什么时候开始,什么时候结束,对应记忆 NAT 映射的开始和结束。

但是基于 UDP 传输的 HTTP3 ,不存在 SYN/FIN 状态位。NAT 设备的记忆如果短于用户会话时间,则用户会话会中断。NAT 设备的记忆时间如果长于用户会话时间,则意味着 NAT 设备的端口资源会被白白占用。

最直接的解决方案是,在 QUIC 的头部模仿 TCP 的 SYN/FIN 状态,让沿途的 NAT 设备知道会话什么时候开始、什么时候结束。但这需要升级全球所有的 NAT 设备的软件。

另外一个可行的方案是,让 QUIC 周期性地发送 Keepalive 消息,刷新 NAT 设备的记忆,避免 NAT 设备自动释放。

NAT 设备禁用 UDP

在一些 NAT 网络环境下(如某些校园网),UDP 协议会被路由器等中间网络设备禁止,这时客户端会直接降级,选择 HTTPS 等备选通道,保证正常业务请求。

NGINX 负载均衡问题概念

QUIC 客户端存在网络制式切换,就算是同一个移动机房,可能第一次业务请求时会落到 A 这台服务器,后续再次连接,就会落到 B 实例上,重复走 1-RTT 的完整握手流程。

全局握手缓存

为所有 QUIC 服务器实例建立一个全局握手缓存。当用户网络发生切换时,下一次的业务请求无论是落到哪一个机房或哪一台实例上,握手建连都会是 0-RTT。


历代 HTTP 速度测试

结尾

从古至今实时数据传输(音频、视频、游戏等)都面临卡顿、延迟等问题,而 QUIC 基于 UDP 的架构和改进的重传等特性,能够有效的提升用户体验。目前
B 站 也已经接入 QUIC。

如果想要自己体验 QUIC,可以使用 Libquic、Caddy 等。另外 github 上面也有 C++版本的 QUIC 实现,利用 Nodejs 的 C++ 模块,前端工程师也可以快速实现一个 node-quic。


参考资料
  1. http2.0 原理详细分析

  2. HPACK: HTTP/2 里的沉默杀手

  3. QPACK:HTTP /3 的头压缩

  4. DH 算法

  5. 前向安全(ForwardSecrecy)

  6. TLS 1.3 VS TLS 1.2,让你明白 TLS 1.3 的强大

  7. CaddyWeb 服务器 QUIC 部署

  8. 关于 QUIC 的各种尝试

  9. 使用 QUIC 协议实现实时视频直播 0 卡顿

  10. 解密 HTTP/2 与 HTTP/3 的新特性

  11. Web通信协议,你还需要知道:SPDY 和 QUIC

  12. 如何看待 HTTP/3 ?


一文读懂什么是机器学习--1. 机器学习是什么?

一文读懂什么是机器学习--1. 机器学习是什么?

 
 
技术分享图片

一文读懂什么是机器学习--1. 机器学习是什么?

一文读懂什么是机器学习--2. 机器学习的范围?

一文读懂什么是机器学习--3. 机器学习的方法?

一文读懂什么是机器学习--4. 机器学习的应用及其子类?


本系列转自微信公众账号机器学习算法与Python学习

转自微信工作账号机器学习算法与Python学习

在进入正题前,我想大家心中可能会有一个疑惑:机器学习有什么重要性,以至于要阅读完这篇非常长的文章呢?

我并不直接回答这个问题前。相反,我想请大家看两张图:

 

 
技术分享图片
图1  机器学习界的执牛耳和互联网界大鳄的联姻

这幅图上的三人是当今机器学习界的执牛耳者。中间的是Geoffrey Hinton, 加拿大多伦多大学的教授,如今被聘为“Google大脑”的负责人。右边的是Yann LeCun, 纽约大学教授,如今是Facebook人工智能实验室的主任。而左边的大家都很熟悉,Andrew Ng,中文名吴恩达,斯坦福大学副教授,也是前“百度大脑”的负责人与百度首席科学家。

这三位都是目前业界炙手可热的大牛,被互联网界大鳄求贤若渴的聘请,足见他们的重要性。而他们的研究方向,则全部都是机器学习的子类--深度学习。

 
技术分享图片
图2 语音助手产品

这幅图上描述的是什么?Windows Phone上的语音助手Cortana,名字来源于《光环》中士官长的助手。相比其他竞争对手,微软很迟才推出这个服务。Cortana背后的核心技术是什么,为什么它能够听懂人的语音?事实上,这个技术正是机器学习。机器学习是所有语音助手产品(包括Apple的siri与Google的Now)能够跟人交互的关键技术。

通过上面两图,我相信大家可以看出机器学习似乎是一个很重要的,有很多未知特性的技术。

一个故事说明什么是机器学习.

机器学习这个词是让人疑惑的,首先它是英文名称Machine Learning(简称ML)的直译,在计算界Machine一般指计算机。这个名字使用了拟人的手法,说明了这门技术是让机器“学习”的技术。但是计算机是死的,怎么可能像人类一样“学习”呢?

传统上如果我们想让计算机工作,我们给它一串指令,然后它遵照这个指令一步步执行下去。有因有果,非常明确。但这样的方式在机器学习中行不通。机器学习根本不接受你输入的指令,相反,它接受你输入的数据 !  也就是说,机器学习是一种让计算机利用数据而不是指令来进行各种工作的方法。这听起来非常不可思议,但结果上却是非常可行的。

接下来这个例子来源于我真实的生活经验,我在思考这个问题的时候突然发现它的过程可以被扩充化为一个完整的机器学习的过程,因此我决定使用这个例子作为所有介绍的开始。这个故事称为“等人问题”。

我一个朋友小Y,他不是那么守时,最常见的表现是他经常迟到。当有一次我跟他约好3点钟在某个麦当劳见面时,在我出门的那一刻我突然想到一个问题:我现在出发合适么?我会不会又到了地点后,还要花上30分钟去等他?

我决定采取一个策略解决这个问题。

我把过往跟小Y相约的经历在脑海中重现一下,看看跟他相约的次数中,迟到占了多大的比例。而我利用这来预测他这次迟到的可能性。如果这个值超出了我心里的某个界限(阈值),那我选择等一会再出发。

假设我跟小Y约过5次,他迟到的次数是1次,那么他按时到的比例为80%,我心中的阈值为70%,我认为这次小Y应该不会迟到,因此我按时出门。如果小Y在5次迟到的次数中占了4次,也就是他按时到达的比例为20%,由于这个值低于我的阈值,因此我选择推迟出门的时间。

这个方法从它的利用层面来看,又称为经验法。在经验法的思考过程中,我事实上利用了以往所有相约的数据。因此也可以称之为依据 数据 做的判断。依据数据所做的判断跟机器学习的思想根本上是一致的。

刚才的思考过程我只考虑“频次”这种属性。在真实的机器学习中,这可能都不算是一个应用。一般的机器学习模型至少考虑两个量:一个是因变量(是否迟到),也就是我们希望预测的结果,在这个例子里就是小Y迟到与否的判断。另一个是自变量(为什么迟到),也就是用来预测小Y是否迟到的量。

假设我把时间作为自变量,譬如我发现小Y所有迟到的日子基本都是星期五,而在非星期五情况下他基本不迟到。于是我可以建立一个模型,来模拟小Y迟到与否跟日子是否是星期五的概率。见下图:

 

 
技术分享图片
图3 决策树模型

这样的图就是一个最简单的机器学习模型,称之为决策树。

当我们考虑的自变量只有一个时,情况较为简单。如果把我们的自变量再增加一个。例如小Y迟到的部分情况时是在他开车过来的时候(你可以理解为他开车水平较臭,或者路较堵)。于是我可以关联考虑这些信息。建立一个更复杂的模型,这个模型包含两个自变量与一个因变量。

再更复杂一点,小Y的迟到跟天气也有一定的原因,例如下雨的时候,这时候我需要考虑三个自变量。

如果我希望能够预测小Y迟到的具体时间,我可以把他每次迟到的时间跟雨量的大小以及前面考虑的自变量统一建立一个模型。于是我的模型可以预测值,例如他大概会迟到几分钟。这样可以帮助我更好的规划我出门的时间。在这样的情况下,决策树就无法很好地支撑了,因为决策树只能预测离散值。我们可以用一文读懂什么是机器学习--3. 机器学习的方法?所介绍的线型回归方法建立这个模型。

如果我把这些建立模型的过程交给电脑。比如把所有的自变量和因变量输入,然后让计算机帮我生成一个模型,同时让计算机根据我当前的情况,给出我是否需要迟出门,需要迟几分钟的建议。那么计算机执行这些辅助决策的过程就是机器学习的过程。

通过上面的分析,可以看出机器学习与人类思考的经验过程是类似的,不过它能考虑更多的情况,执行更加复杂的计算。事实上,机器学习的一个主要目的就是把人类思考归纳经验的过程转化为计算机通过对数据的处理计算得出模型的过程。经过计算机得出的模型能够以近似于人的方式解决很多灵活复杂的问题。

让我们把机器学习的过程与人类对历史经验归纳的过程做个比对。

 

 
技术分享图片
图4 机器学习与人类思考的类比

机器学习中的“训练”与“预测”过程可以对应到人类的“归纳”和“推测”过程。通过这样的对应,我们可以发现,机器学习的思想并不复杂,仅仅是对人类在生活中学习成长的一个模拟。由于机器学习不是基于编程形成的结果,因此它的处理过程不是因果的逻辑,而是通过归纳思想得出的相关性结论。

以上是关于一文读懂 HTTP/1HTTP/2HTTP/3的主要内容,如果未能解决你的问题,请参考以下文章

一文读懂 NMEA-0183 协议数据

一文读懂 NMEA-0183 协议数据

一文读懂 NMEA-0183 协议数据

一文读懂所有HTTP状态码含义

一文读懂LiveData 的粘性事件

激光雷达是什么?一文带你读懂激光雷达