写点什么

HTTP/2 探索第一篇——概念

2019 年 8 月 22 日

HTTP/2探索第一篇——概念

一、现状


1. 网络性能


现在网络优化的瓶颈是什么?你可能会说,带宽。也许在 2014 年前,决定性能的关键是带宽,但是在今天以及以后,瓶颈都不会是带宽,而是延迟;



从图中可以看出,随着带宽的增长,页面加载时间(PLT Page Load Time)在 1Mbps 到 3Mbps 的区间得到了很大的改善,但是再提高带宽,带来的提升就很小了,属于非线性改善;反观延迟,延迟(这里是指多个 RTT 时间相加的总和)的改善对于页面加载时间是属于线性改善;


HTTP/1.1 TCP 连接是需要三次握手的,同时,多个 TCP 连接也会给服务器带来资源的消耗,在 HTTP/1.1 中,每个请求回复都是一次 TCP 连接(未开启 Keep-Alive 的情况下),并且,同时传输多个资源时,会有队首阻塞的问题,造成网络资源无法有效利用;


2. 安全


对于大多数人来说,下图的情况几乎都有遇到过(电脑或手机里)。万恶的运营商或者网络接入 WiFi 提供商劫持我们的网络,修改网络的内容,给我们带来了很大的困扰;



二、HTTP/2.0


现在,HTTP/2.0 出现了。其实 HTTP/2.0 是支持 Clear Text 版和 Over TLS 版,由于现有支持 HTTP/2.0 的浏览器都是实现的 Over TLS 版,故本文的 HTTP/2.0 都是讲的是 HTTPS 版 HTTP/2.0;


1. Clear Text 版:


客户端向服务端请求(假设此时 scheme 是 HTTP),带有以下头:


Upgrade: h2c


HTTP2-Settings


服务器端返回:


101 状态码,转换协议;


Connection: Upgrade


Upgrade: h2c 或者 200/404


2. HTTP/2.0 Over TLS 版:


客户端向服务器端请求


TLS + ALPN(Application Layer Protocol Negotiation)/NPN


服务器端返回:


TLS 握手 并返回支持的 HTTP 协议;


a. TLS 握手详细过程



b. ALPN 协商过程


参考 TLS 握手过程图,下面是增加 ALPN 协商的具体过程:


客户端添加一个 ProtocolNameList 字段,包含支持的 HTTP 协议到 ClientHello 消息中;


服务器端查看 ProtocolNameList 字段后通过 ServerHello 消息返回 ProtocolName 字段,表明被选定的协议;


通过实现 ALPN,不再需要单独请求一次服务器带上 Upgrade: h2c;


c. False Start


通常情况下,使用 ALPN 会搭配使用 False Start,客户端在完成 TLS 握手前提前发送加密后的应用数据,将两次 RTT TLS 握手减少为一次;不过需要同时支持 ALPN(NPN 已经很少用啦)和前向安全性;


d. HSTS


HTTP Strict Transport Security(简称为 HSTS)是一个安全功能,告诉浏览器只能通过 HTTPS 访问当前资源,禁止 HTTP 方式。


如果用户输入域名www.qq.com,浏览器首先会去请求http://www.qq.com,请求过程是明文非加密的,此时容易被中间人攻击,让网路恶意中间商直接接触到用户信息;而 HSTS 是用户请求时,服务器告诉客户端,下次来请求直接请求 https://,而不要再请求服务器来跳转到 https;


同时,开启 HSTS 后,如果证书认证不通过(比如遭到中间人攻击),浏览器此时强制无法打开该网站;


3. 名词解释


流(Stream):一个 Stream 是包含一条或多条信息,ID 和优先级的双向通道;


消息(Message):消息由帧组成;


帧(Frame):帧有不同的类型,并且是混合的。他们通过 stream id 被重新组装进消息中;


4. 概念解释


a. 二进制帧



HTTP2 的二进制帧是 9 字节(72 bit)


长度:24bit,也就是理论上可以携带 2^24 字节的数据。但通常由于 SETTINGS_MAX_FRAME_SIZE 的设置,不能发送超过 2^14(16384)字节的数据;


类型:8bit,决定了该帧的类型;


DATA : 数据帧


HEADERS : 头部帧


PRIORITY : 设置流的优先级


RST_STREAM : 终止流


SETTINGS : 设置连接参数


PUSH_PROMISE : 服务器推送模拟请求帧


PING : 用来计算 RTT 时间和看是否服务器挂了的 Stream


GOAWAY : 告诉对方停止再向当前连接创建 stream


WINDOW_UPDATE : 流量控制


保留字段:1bit,一般为 0;


Stream ID:31bit,Stream 标识,理论上可以有 2147483648,超过这么多 stream 怎么办呢?


如果是客户端无法再创建新的 stream id,可以直接创建新的 TCP 连接,stream id 被重置;


如果是服务器端无法再创建新的 stream id,服务器将会给客户端发一个 GOAWAY 帧,客户端无法再向该服务器创建 stream,不得不新建 TCP 连接;


5. 新特性


多路复用


头部压缩


资源优先级/依赖关系


流量控制


Server Push(客户端请求一个路径时,服务器推送一个资源给客户端)


a. 多路服用



HTTP/2.0 中,数据在发送端被切分为更小的数据帧用以高效利用链接;


HTTP 1.1 时代,再不开启 Keep-alive 的情况下,每一个请求会占用一个 TCP 连接,而 HTTP/2 将请求和响应消息拆分为各自独立的帧,交错的发送,然后再在接收端重新装配组合。有什么好处呢?


交错的多个请求/响应之间互现不会被阻塞


HTTP/1.1 时代的 Keep-alive 也是保持同一个 TCP 连接,但是由于请求/接收有先后,后面的请求资源会被前面的资源阻塞(没收到响应时不会发新的请求),如下图最左和最右边所示,即便是相比 HTTP 管道,优化也是巨大的:



减少了不必要的延时,改善了网路的利用率(多路复用和资源优先级/依赖关系搭配使用,使得页面重度依赖的资源优先传输);


b. 头部压缩


HTTP/2.0 使用 HPACK 来给头部压缩;


值通过霍夫曼编码;


之前发送的值都被索引起来,之后使用时发现之前发送过该 Header 字段,并且值相同,就会沿用之前的索引来指代那个 Header 值;


Cookies:在 HTTP/2.0 中,Cookie 也将会变为键值对索引起来,而不是一长串字符串;


可以看看我们组 dream 同学的 HTTP/2.0 之特性科普篇——头部压缩,里面有截图部分的数据讲述压缩后的效果;



这里需要讲解一下伪头部字段:


请求:


:authority


:method


:path


:scheme


响应:


:status


所有的伪头部字段都是在所有 Header 的前部;


c. 资源优先级/依赖关系


资源优先级/依赖关系通过 stream 权重和 dependency 来设置;



通过上图可以看到,有一列是叫作 Priority,初始设置是根据 Content-type 来设置优先级的,比如 HTML 是 Highest,CSS 是 High,然后 JS 是 Medium;


Stream 权重值可以设置为 1 到 256 之间;


Stream 可以明确的表示依赖关系;


注意,一定要理解权重和依赖,权重值和依赖关系是作为带宽资源/服务器/客户端处理资源的建议值,但并不能保证他们有特定的传输顺序。让我们来看一张 HTTP/2.0 的依赖关系和权重图:



HTTP/2.0 中的 stream 都默认是依赖于一个根 stream(其实不存在)。权重值是针对同级来计算的,不同级是不用来计算的;


d. 流量控制


与 TCP 的流量控制类似,不过 HTTP/2.0 的流量控制可以到具体帧,而 TCP 是 TCP 连接层面上的。注意:流量控制目前只对 DATA 帧有效!流量控制的算法没有具体要求使用哪一种,但是大概实现的功能是这样的:


两端收发保有一个流量控制(window)窗口;


发送端每发送一个 DATA 帧,就把窗口的大小递减,递减量为这个帧的大小,要是窗口大小小于该帧的大小,那么这个帧就必须被拆分。如果窗口值等于 0,就不能发送任何帧。流量控制的初始默认窗口值大小为 65535 字节(理论上可以设置 2^31-1 字节也就是 2147483647 字节大小的窗口值)。


接收端可以通过发送 WINDOW_UPDATE 帧给发送端,发送端以帧内指定的窗口大小增量加到窗口大小限制上。


e. Server Push


Server Push 的资源同样需要遵守同源策略,通过:authority 来判断;



如 Demo 里所示,如果在服务器端设置当请求 Path/examples/dashboard 时就推送/examples/dashboard/d3.js,现在我们来看抓包:



说明:


当客户端请求服务器时(此时的请求路径已经设置好推送),服务器发回一个 PUSH_PROMISE 和两个 HEADERS Frame,从 Stream Identifier 可以看出,第一个 HEADERS 的 Stream ID 是 1,也就是复用请求的 Stream 来返回(这是 HTML 文件的返回响应 Header)。第二个 HEADERS 就是推送文件的响应 Header。


根据定义,由客户端初始化发起的 Stream 的标识符是奇数,由服务器端初始化发起的 Stream 是偶数,图中可以体现;


那么 Stream 1 和 Stream 2 的顺序如何保证呢?说明文档里有这样一句话:


Pushed streams initially depend on their associated stream.


也就是说,服务器将要推送的资源依赖于触发推送的请求,根据 Stream 依赖的功能,只有被依赖的 stream 加载完后才会去加载接下来的 stream;


Server Push 有什么好处呢:


推送的资源可以被客户端缓存;


推送的资源可以被不同的页面复用;


推送资源也是支持多路复用的;


推送资源可以被客户端拒绝掉(客户端接收到 PUSH_PROMISE 后,可以选择发送 RST_PROMISE 来拒绝接收,告诉服务器端不要再发送了,当然,此时可能已经有部分内容已经发送过来了);


同时,Server Push 配合流量控制,可以实现很多很神奇的功能,这里卖个关子,然后会在下一篇讲解 :)


本文转载自公众号小时光茶舍(ID:gh_7322a0f167b5)。


原文链接:


https://mp.weixin.qq.com/s/Y1x0GUkfRbWEz6YsJrMTAQ


2019 年 8 月 22 日 19:062573

评论

发布
暂无评论
发现更多内容

C2C交易系统APP开发|C2C交易软件开发

开發I852946OIIO

系统开发

RocketMQ解析

石刻掌纹

基因编辑食品,能否端上我们的餐桌?

脑极体

android开发要学什么语言!掌握这些Android开发热门前沿知识,挥泪整理面经

欢喜学安卓

android 程序员 面试 移动开发

Java架构师必会的知识清单,如何让你技术上的提升面试时的丰收

Crud的程序员

Java 架构 java程序员

编程语言学习心得 (完全版) -- 不要害怕遗忘和混淆

蔡超

程序员 个人成长 编程语言 go语言

爱了爱了!阿里爆款Spring进阶宝典,涵盖其所有技术栈(源码+实战彻底玩转Spring框架)

Java架构之路

Java 程序员 架构 面试 编程语言

RocketMQ源码分析之消息拉取流程

互联网架构师小马

JVM内存模型总结和上手实践,亲测学完没脱发

互联网架构师小马

现成矿机挖矿软件系统APP开发案例

开發I852946OIIO

系统开发

产品经理训练营笔记-认识产品经理(上)

.nil?

week8-conclusion

J

做事情的三条边

石云升

28天写作 基线 极限

写在开课前

5x

「架构师训练营 4 期」 第三周 - 001

凯迪

python自学 第二章 python语言基础之语法特点(注释、代码缩进、编码规范)

WEB前端修行日志

Python 编码格式

线上问题排查学习总结

原来不悔

Java Linux

android进阶之光!双非渣本Android四年磨一剑,进阶学习资料!

欢喜学安卓

android 程序员 面试 移动开发

python自学 第四章 python语言基础之变量

WEB前端修行日志

Python 编码格式

非科班生的逆袭:四面斩获字节跳动offer,聊聊我的个人历程

互联网架构师小马

Java 面试 算法 操作系统 计算机组成原理

区块链交易所系统开发|区块链交易所软件APP开发

开發I852946OIIO

系统开发

如何实现CentOS服务器的扩容??

冰河

Linux centos 扩容 服务器

Lambda 和 Stream API

学个球

Lambda Java 8 Stream<T>

「架构师训练营 4 期」 第三周 - 002

凯迪

使用 JSX 建立 Markup 组件风格

三钻

组件化 前端进阶

python自学 第三章 python语言基础之保留字、标识符与内置函数

WEB前端修行日志

Python 编码格式

Android面试总结(一)

举头三尺有维尼

企业业务系统开发(1)

dowell87

28天写作

游戏夜读 | 游戏作品的生命力

game1night

创业失败启示录|校园微生活之校园女神

青城

28天写作 创业失败启示录

一款dubbo服务可视化调试工具

程序员架构进阶

dubbo 工具 RPC 服务化 28天写作

HTTP/2探索第一篇——概念-InfoQ