干货--HTTP 1.01.12.0详解

Posted JAVA干货分享

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货--HTTP 1.01.12.0详解相关的知识,希望对你有一定的参考价值。

开篇


        试想一下,一个科班出身,拥有丰富开发经验的程序员对于HTTP协议却不甚了解?还是很尴尬的!这么一个可以说是常识的问题,可能很多人在没有积极准备的情况下,不一定能很好的回答出来。这是一个正规程序员所本应了解的原理,如果一个程序员在这些常识性的问题上都没有很好的思考,那么在以后的职业发展中未必能更好的承担更高难度的工作。功夫在细节,谁说不是呢?


Http的历史

        HTTP(超文本传输协议,HyperText Transfer Protocol)是建立在TCP协议之上的一种应用层网络协议。默认使用80端口,建立之初目的是为了将超文本标记语言(html)文档从Web服务器传送到客户端的浏览器。WEB2.0以后,页面变得越来越复杂,以及ajax的出现提供了一种向服务端获取数据的新方式,这些推动着HTTP协议不断扩展功能、不断优化性能:

  • HTTP/0.9:1991年发布,极其简单,只有一个get命令;

  • HTTP/1.0:1996年5月发布,增加了大量内容;

  • HTTP/1.1:1997年1月发布,进一步完善HTTP协议,是目前最流行的版本;

  • SPDY :2009年谷歌发布SPDY协议,主要解决HTTP/1.1效率不高的问题;

  • HTTP/2 :2015年借鉴SPDY的HTTP/2发布。

Http的优化

        HTTP协议建立在TCP协议之上,所以HTTP协议的瓶颈及其优化技巧都是基于TCP协议本身的特性,比如TCP的三次握手和四次挥手以及每次建立连接带来的RTT延迟时间。

影响一个HTTP网络请求的因素主要有两个:带宽和延迟:

  • 带宽:网络带宽是指单位时间内传输的数据量,是数据的传输能力。现在网络基础建设较为完善,基本不用担心带宽影响网速,所以目前影响HTTP网络请求性能的就是延迟了。

  • 延迟:
    1. 浏览器阻塞(head of line blocking):浏览器会因为一些原因阻塞请求。浏览器对于同一个域名,同时只能有 6个连接(这个根据浏览器内核不同可能会有所差异),超过浏览器最大连接数限制,后续请求就会被阻塞。这也是为何一些站点会有多个静态资源 CDN 域名的原因之一。
    2. DNS查询(DNS Lookup):将域名解析为IP就是DNS查询,一般使用DNS缓存来减少这个时间。
    3. 建立连接(Initial connection):HTTP 是基于 TCP 协议的,浏览器最快也要在第三次握手时才能携带 HTTP 请求报文,达到真正的建立连接,但是这些连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对文件类大请求影响较大。

HTTP1.0


        显 然,访问一个包含有许多图像的网页文件的整个过程包含了多次请求和响应,每次请求和响应都需要建立一个单独的连接,每次连接只是传输一个文档和图像,上一次和下一次请求完全分离。即使图像文件都很小,但是客户端和服务器端每次建立和关闭连接却是一个相对比较费时的过程,并且会严重影响客户机和服务器的性能。当一个网页文件中包含javascript文件,CSS文件等内容时,也会出现类似上述的情况。


        同时,带宽和延迟也是影响一个网络请求的重要因素。在网络基础建设已经使得带宽得到极大的提升的当下,大部分时候都是延迟在于响应速度。基于此会发现,http1.0被抱怨最多的就是连接无法复用,和head of line blocking这两个问题。理解这两个问题有一个十分重要的前提:客户端是依据域名来向服务器建立连接,一般PC端浏览器会针对单个域名的server同时建立6~8个连接,手机端的连接数则一般控制在4~6个。

        显然连接数并不是越多越好,资源开销和整体延迟都会随之增大。连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对文件类大请求影响较大。head of line blocking会导致带宽无法被充分利用,以及后续健康请求被阻塞。

head of line blocking(holb)会导致健康的请求会被不健康的请求影响,而且这种体验的损耗受网络环境影响,出现随机且难以监控。为了解决holb带来的延迟,协议设计者设计了一种新的pipelining机制。pipelining只能适用于http1.1,而且由于使用苛刻,很多浏览器厂商并不支持。


HTTP1.1


支持持久链接(在request和response中的header中的connection是close或者Keep-Alive进行控制)

        一个TCP链接可以传送多个http请求和相应,减少了TCP建立链接和关闭链接的消耗。另外http1.1允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能      够区分出每次请求的响应内容。


支持http管道

        不使用管道的http请求,在使用持久链接时,必须严格满足先进先出的队列顺序(FIFO),即发送请求,等待响应完成,再发送客户端队列中的下一个请求。管道可以让我们把 FIFO 队列从客户端(请求队列)迁移到服务器(响应队列),即客户端可以并行,服务端串行。客户端可以不用等待前一个请求返回,发送请求,但服务器端必须顺序的返回客户端的请求响应结果。

缺点:

    a. 一个请求响应阻塞,就会阻塞后续所有请求

    b. 并行处理请求时,服务器必须缓冲管道中的响应,从而占用服务器资源,如果有个响应非常大,则很容易形成服务器的受攻击面;

    c. 响应失败可能终止 TCP 连接,从页强迫客户端重新发送对所有后续资源的请求,导致重复处理;

    d. 由于可能存在中间代理,因此检测管道兼容性,确保可靠性很重要;

    e. 如果中间代理不支持管道,那它可能会中断连接,也可能会把所有请求串联起来。


使用多个TCP链接

        http1.1 在客户端排队所有请求,然后通过一个TCP持久链接,一个接一个的发送请求(如果有http管道还必须顺序等待服务端的顺序返回结果)。但实际中,浏览器的开发时不会这么笨,浏览器允许我们打开N个TCP链接(大多说浏览器是6个TCP链接,这个数字越大,客户端和服务器的资源占用越多,这个数据也只是感觉安全的数字而已)。

带来的好处:
  1. 客户端可以并行发送最多 N个请求;

  2. 服务器可以并行处理最多 N个请求;

  3. 第一次往返可以发送的累计分组数量(TCP cwnd)增长为原来的 N 倍。

代价:

    1.更多的套接字会占用客户端、服务器以及代理的资源,包括内存缓冲区和 CPU时钟周期;

    2.并行 TCP 流之间竞争共享的带宽;

    3.由于处理多个套接字,实现复杂性更高;

    4.即使并行 TCP 流,应用的并行能力也受限制。

因此使用多个TCP链接只是权宜之计,后续的http 2.0支持多路复用,很好的解决了上述问题。


http 1.1 增加了请求头和响应头来扩充功能

举例:

    a. 支持Host请求:

    b. Connection: 请求头的值为Connection时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close 时,客户端通知服务器返回本次请求结果后关闭连接

    c. 支持断点续传:

    d.身份认证:

    e.状态管理:

    f. 缓存处理:

域名分区

    域名分区是思想是将原来集中到一个服务器上的资源分布到多个服务器上,这样就可以突破浏览器的链接限制(一般是6个),提高并行能力。

代价:

  1. 每多一台主机都要多一次的 DNS 查询,每多一个套接字都会多消耗两端的一些资源;

    2.必须手工分离一台主机上的资源到多台;.

实际实践中,效果并不是很明显,反而导致被滥用。


http的header的优化

        目前所有的header请求都是以没有经过压缩的纯文本的形式发送(通常会有600`1000字节),而通常使用的http请求body却很少(10~200字节),和header相比,显得很少,特别是在使用了cookie之后,这样的矛盾就更加突出,因此要减少header的数据。


减少连接次数

        即将需要多次才能获取的文件或资源组合并成一个,通过一次网络请求获取。这样减少了协议的开销,间接地将服务器端的管道思维移植到了客户端。缺点:增加复杂性,更缓存带来负担,页面的分步显示,改成一次显示,在网络慢的时候影响用户体验。

嵌入小的文件

        即将资源嵌入文档(通过URI嵌入图片,音频或PDF),可以减少请求次数。嵌入资源作为页面的返回一部分一次返回,即如果在多个页面中都嵌入同样的资源,那么这个资源将会随着每个页面的加载而被加载,从而增大每个页面的总体大小,如果嵌入资源被更新,客户端只能重新获取有效的资源。

实践:一般只考虑嵌入1~2KB一下的资源

参照建议:
  1. 如果文件很小,而且只有个别页面使用,可以考虑嵌入;

    2.如果文件很小,但需要在多个页面中重用,应该考虑集中打包;

  1. 如果小文件经常需要更新,就不要嵌入了;

  2. 通过减少 HTTP cookie 的大小将协议开销最小化。


HTTP2.0


介绍

        HTTP/2是HTTP协议自1999年HTTP1.1发布后的首个更新,主要基于SPDY协议。

什么是SPDY协议

        SPDY是Speedy的昵音,意为“更快”。它是Google开发的基于TCP协议的应用层协议。目标是优化HTTP协议的性能,通过压缩、多路复用和优先级等技术,缩短网页的加载时间并提高安全性。SPDY协议的核心思想是尽量减少TCP连接数。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。


HTTP1.X的缺点

        任何事物的更新都是为了弥补或修复上个版本的某些问题,那么我们来看看HTTP1.x都有哪些缺点以至于我们要使用HTTP2.0。

HTTP1.x有以下几个主要缺点:

  1. HTTP/1.0一次只允许在一个TCP连接上发起一个请求,HTTP/1.1使用的流水线技术也只能部分处理请求并发,仍然会存在队列头阻塞问题,因此客户端在需要发起多次请求时,通常会采用建立多连接来减少延迟。

  2. 单向请求,只能由客户端发起。

  3. 请求报文与响应报文首部信息冗余量大。

  4. 数据未压缩,导致数据的传输量大

二进制分帧

        在不改变HTTP1.x的语义、方法、状态码、URL以及首部字段的情况下,HTTP2.0是怎样突破HTTP1.1的性能限制,改进传输性能,实现低延迟高吞吐量的呢?关键之一就是在应用层(HTTP)和传输层(TCP)之间增加一个二进制分帧层。

在整理二进制分帧及其作用的时候我们先来铺垫一点关于帧的知识:

  • 帧:HTTP2.0通信的最小单位,所有帧都共享一个8字节的首部,其中包含帧的长度、类型、标志、还有一个保留位,并且至少有标识出当前帧所属的流的标识符,帧承载着特定类型的数据,如HTTP首部、负荷、等等。

  • 消息:比帧大的通讯单位,是指逻辑上的HTTP消息,比如请求、响应等。由一个或多个帧组成

  • 流:比消息大的通讯单位。是TCP连接中的一个虚拟通道,可以承载双向的消息。每个流都有一个唯一的整数标识符

HTTP2.0中所有加强性能的核心是二进制传输,在HTTP1.x中,我们是通过文本的方式传输数据。基于文本的方式传输数据存在很多缺陷,文本的表现形式有多样性,因此要做到健壮性考虑的场景必然有很多,但是二进制则不同,只有0和1的组合,因此选择了二进制传输,实现方便且健壮。
在HTTP2.0中引入了新的编码机制,所有传输的数据都会被分割,并采用二进制格式编码。

为了保证HTTP不受影响,那就需要在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。在二进制分帧层上,HTTP2.0会将所有传输的信息分为更小的消息和帧,并采用二进制格式编码,其中HTTP1.x的首部信息会被封装到Headers帧,而Request Body则封装到Data帧。


首部压缩

        HTTP1.1并不支持HTTP首部压缩,为此SPDY和HTTP2.0出现了。SPDY是用的是DEFLATE算法,而HTTP2.0则使用了专门为首部压缩设计的HPACK算法。

        HTTP每次通讯(请求或响应)都会携带首部信息用于描述资源属性。

        在HTTP1.0中,我们使用文本的形式传输header,在header中携带cookie的话,每次都需要重复传输几百到几千的字节,这着实是一笔不小的开销。

        在HTTP2.0中,我们使用了HPACK(HTTP2头部压缩算法)压缩格式对传输的header进行编码,减少了header的大小。并在两端维护了索引表,用于记录出现过的header,后面在传输过程中就可以传输已经记录过的header的键名,对端收到数据后就可以通过键名找到对应的值。

多路复用

        在HTTP1.x中,我们经常会使用到雪碧图、使用多个域名等方式来进行优化,都是因为浏览器限制了同一个域名下的请求数量,当页面需要请求很多资源的时候,队头阻塞(Head of line blocking)会导致在达到最大请求时,资源需要等待其他资源请求完成后才能继续发送。

        HTTP2.0中,基于二进制分帧层,HTTP2.0可以在共享TCP连接的基础上同时发送请求和响应。HTTP消息被分解为独立的帧,而不破坏消息本身的语义,交错发出去,在另一端根据流标识符和首部将他们重新组装起来。通过该技术,可以避免HTTP旧版本的队头阻塞问题,极大提高传输性能。

请求优先级

        把HTTP消息分为很多独立帧之后,就可以通过优化这些帧的交错和传输顺序进一步优化性能。

服务器推送

        HTTP2.0新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确的请求。

        服务端根据客户端的请求,提前返回多个响应,推送额外的资源给客户端。如下图,客户端请求stream 1(/page.html)。服务端在返回stream 1的消息的同时推送了stream 2(/script.js)和stream 4(/style.css)

        服务端推送是一种在客户端请求之前发送数据的机制。在HTTP2.0中,服务器可以对一个客户端的请求发送多个响应。如果一个请求是由你的主页发送的,服务器可能会响应主页内容、logo以及样式表,因为他知道客户端会用到这些东西。这样不但减轻了数据传送冗余步骤,也加快了页面响应的速度,提高了用户体验。

        推送的缺点:所有推送的资源都必须遵守同源策略。换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方的确认才行。

写在最后:

                                


以上是关于干货--HTTP 1.01.12.0详解的主要内容,如果未能解决你的问题,请参考以下文章

精选干货SpringMVC详解——详细架构

(转) Java中的负数及基本类型的转型详解

详解Android WebView加载html片段

干货 | OpenCV中KLT光流跟踪原理详解与代码演示

#yyds干货盘点# Spring AOP详解

干货 | 23种设计模式详解,助你优雅写代码!