Http协议的发展与经过

一、前语

网络协议有很多种,对于互联网来说,用的最多的就是http协议了,http主要有http1.0、http1.1、http/2三个主流版本,在http之上,又有Https。那么,http各个版本有什么不同?https又是什么东西?QUIC是啥?接下来,我将对http协议发展的脉络进行一个简单的梳理。

1996年、http1.0协议规范rfc1945发布。

1999年、http1.1协议规范rfc2616发布。

2015年、http/2协议规范rfc7540/7541发布、

时至今日,http/2还是比较新的,普及度还是不够,过去的20年,主流的http协议版本还是1.1。既然脉络梳理,咱们就从http1.0说起吧。

二、http1.0协议

http协议的基本特点就是“一来一回”,或者说request/response。每一个请求/响应后,连接关闭。大家都知道,http是基于tcp协议的,http的请求相应其实就是客户端发送一个tcp链接,服务端响应后,然后链接关闭。链接建立与关闭都是耗时操作。每一个网页,不仅仅有html,还有各种各样的图片、css、js文件。每一个文件都会引发至少一个http请求。虽然现在的浏览器都可以同时开多个链接,并发发送请求,但服务端链接量毕竟是有限的。

1、链接复用:

为了解决频繁的创建连接引发的性能问题,Http1.0设计一个Keep-alive机制,就是说,浏览器在发送请求的时候,head中带上Connection:Keep-Alive。服务器收到这样的请求后,处理完成请求内容,不在关闭连接,在返回请求的时候,也带上该字段,然后等待客户端发送下一个请求。于是,一个新的问题引发了,如果链接不关闭的话,服务器的连接数是有限的,很快,链接就被耗光了。因此服务器会有一个参数Keep-Alive timeout参数,其含义是,制定一个链接过期时间,如果本段时间内,没有新的请求发送过来,服务器就关闭连接。

2、Content-Length

新的问题出现了,连接可以复用了,但是,客户端如何知道自己的数据接收完整了呢?答案是:服务器在response的时候,加入了一个Content-Length参数,表示响应的内容大小。客户端接收到指定大小的数据后,就明白响应完成了接收完毕了。看似很完美对吧?其实,新的问题出来了,Content-Length好多情况下是动态的,服务器也很难且很耗时地计算自己要发送多长的响应包。

 

Http明面上遗留很多问题:响应内容的大小Content-Length、一来多回、连接不能并发发送等等。所有的问题都留给下一个版本吧。

三、Http1.1协议

考虑到链接复用的必要性,于是,http1.1把Connection:Keep-Alive作为默认请求属性加入了请求head中,除非浏览器在head中加入Connection:Close属性,服务器才会在请求结束后关闭连接。

1、Chunk机制

再来说http1.1如何处理Content-Length的问题,为了解决这个问题,1.1版本引用了Chunk机制(http streaming)。具体地说就是,在response的head中加入Transfer-Encoding:chunked属性。其目的告诉客户端,大小我也不急算了,发一段计算一段,我的响应内容是分块的,块与块之间有间隔符,数据结尾也有也有特殊标记,你客户端自己看着办吧。看一段响应伪数据:

HTTP1.1 200 OK
Transfer-Encoding: chunked
25
this is the data in the first chunked
1C
and this is the second one
3
con
8
hahahaha
0

示例中伪数据中,25 1C 3 8等数字表示分隔符,0表示结束了。这样客户端就能明确的判断具体的响应大小和是否接收完成了。

2、Pipeline机制与head-of-line Blocking问题

连接复用解决了,还有一个问题,请求是串行的,就是说,客户端发送一个请求,收到响应,然后在发送下一个请求...这种串行的方式,导致并发度不够。为此,Http1.1引入了pipeline机制。其原理就是在同一个tcp链接上,允许客户端发送一个请求后,再立即发送下一个请求,不用等上一个请求回来。这样就提高了tcp链接上的请求效率。如下图:

但是,这种方式pipeline的方式,也有一个致命的问题,叫做“head-of-line Blocking”,中文含义就是“队头阻塞”,什么意思呢?如上图客户端发送的123三个请求是并发发送的,服务器响应的时候,也必须按照顺序进行响应。如果请求1阻塞的响应1阻塞了(比如超时了,网络忽然断开了),那么请求2和请求3也会被阻塞。但是,不管如何,这也是http1.1的一大进步。如何解决他?留给下一个版本吧。

3、链接数优化

在之前的内容中,有提到服务器的连接数是有限制的,但是一个网页有好多链接,几十个甚至上百个,浏览器一般都会限制默认智能并发开6-8个,这样来说,网站请求过多,用户体验总归不是很好。为了提高网站的响应速度和用户的体验感受,咱们在开发和运维的时候就必须使用一些应用层面(非协议层面,http2在协议层面对这些问题进行了优化)小技巧来减少浏览器的请求数量:

a、Spriting技术

精灵图,多个小图片合成一个大图片。

b、内联图(inlining)

部分图表图片从html的Dom中抽离,放入css内。如果图片放到dom中,那么图片是dom的一部分,如果图片过大,就会阻塞dom中其他内容的加载。但是如果放到css内,图片是不属于dom结构的,图片会在dom加载完成之后再进行图片的加载。

c、合并请求

其实也叫作js、css资源拼接技术,可以认为的合并,也可以使用程序渲染页面的时候,多个js或css用一个链接渲染。

d、请求分片

资源文件作为独立的网站服务器部署,或cdn技术。

4、一来多回问题

这个问题一直在遗留,1.0没有解决,1.1也没有从根本上解决。但是,人不能被尿憋死吧,办法总比问题多。

a、ajax轮询

效率低,增加服务器请求压力。

b、flashsocket/websocket

不是http,基于tcp,但是浏览器兼容性问题没有解决,比如IE567不一定支持。

c、http长轮询

客户端发送一个请求,如果服务器有新内容,就立即返回,如果没有,不返回,持有该请求一段时间,超时后在返回,然后客户端在立即发送一个请求。

d、chunked

服务器发一个客户端永远接收不完的请求。

e、服务端断点续传(断点下载)问题。

相比http1.0,在1.1版本中,增加了断点续传的功能。客户端一边下载,一边记录下载的数据大小,一旦连接断开,下次链接的时候,就带上这些信息(就是head中加上Range:first offset-last offset),服务端就可以从指定的位置继续下载了。

http1.1里面,断点上传的问题是不适用的,如果需要,需要自己实现。

四、HTTP/2

HTTP/2希望能够提高效率。http1.1留下的pipeline的不够完善(队头阻塞、响应顺序严格一致),Htpp/2想对其进行完善一下。最初是由于google的spdy协议,后来spdy被越来越多的大型网站(谷歌、脸书、推特等)在基础设施内部署。http工作组发现后,感觉很NB,就进行了借鉴,并吸取了spdy的经验和教训,在此基础上,制定了HTTP/2协议。可以看出来,这个版本有很好的的实践基础,之所以叫做HTTP/2,是因为工作组认为,这个协议很完善了,没必要出小版本了,下次再出,直接就是http3.X系列了。咱们接下来看一下http/2的特性:

1、兼容http1.1

比如兼容1.1的url,不能改变1.1的request/response的报文请求结构等等。

2、他和1.1的关系

http1.1是基于tcp的,但是http2为了兼容1.1(至少表现层要兼容),http2直接在tcp和http1.1之间进行的重新构架,就是说,不改变http1.1已经形成的使用方式,我在你的中间去架构。如下

http1.1:tcp------------------------------------>http1.1

http/2  :tcp-------------->spdy------------->http1.1

3、二进制分帧

其实http/2没有解决对头阻塞的问题。但是解决pipeline遗留的请求/响应顺序问题,解决的方式是“二进制分帧”(把一个请求分为好多帧发送给服务器,每个帧上面都带着相同请求的编号,服务器进行组装处理,处理完就返回),他只是把“对头阻塞”问题的粒度有“请求”转化为了“请求帧”(返回或发送的第一帧如果出现问题,仍然会阻塞后续帧),并且对服务器的响应顺序不在严格控制了,可以对多个请求乱序返回。这里我不想细说了,有兴趣的自行查找相关资料。

如果要策底解决队头阻塞问题、google的QUIC协议,后面会说一下其原理。

4、head压缩

随着用户对网站的使用的要求越来越高,应用场景越来越复杂,head报文内容也越来越大,http/2的另一个提升效率的方法就是对http的头部内容进行了压缩。其好处不言而喻。

五、HTTPS 简要概述

不同于http/2是用来解决性能问题的,Https主要解决的是安全问题。其和http2的关系如下图:

可以看到,没有http2,一样可以构建https。整个互联网为了推动https,现在好多浏览器都要求如果想支持http/2,必须先支持https。

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。它被广泛用于万维网上安全敏感的通讯,例如交易支付等方面 。

注:我单独用一篇文章解释https相关的内容:Https实现原理,所以这里只是一个简述。https如果要概述,需要解释ssl/tls协议以及四次握手、加密种类、认证数字证书/证书中心、tcp链接的三次握手与断开的四次握手、ACK回执机制等等问题,每一项都拿出来都可以写一大篇。本篇关于https想具体内容不在深入解释。

六、QUIC协议

QUIC协议“基于UDP的多路并发协议”,前面说了quic协议可以解决队头阻塞。基于tcp的协议不可能解决对头阻塞,因为TCP是“先发先送先接收”,那么为什么“基于UDP的多路并发协议”可以解决?

1、Raid5

由于UDP是不安全的,容易丢包。为了解决丢包问题,quick也对请求分帧,二进制分帧,比如一个请求分为5帧(如A/B/C/D/E),客户端发送的时候,除了发送这5个帧包外,还在发送一个冗余包(其内容是对前5个帧包的异或运算总和,如A+B+C+D+E=Total),这样的话,前5个包如果走丢一个,直接使用冗余包进行差值计算(一元一次方程),就可以得出走丢的包了。这就是RAID5算法。

2、Raid6算法

为了提高安全级别,有人又提出了radi6算法。在raid5里面,是发送一个冗余包,而raid6是发送两个冗余包,构成一个二元一次方程。比如一个请求分为5帧(如A/B/C/D/E),除了发送这5个帧包外,还在发送2个冗余包(其内容是对前5个帧包的异或运算总和,如A+B+C+D+E=Total1和A+B+C+D+E=Total2)。这种方式允许你走丢两个包。

3、0次Rtt(round trip time)

通信一来一回,叫做一个rtt。大家都知道,tcp需要三次握手,其实ssl/tls需要四次握手,也就是说http1.1需要3次握手,https需要7次。但是udp不需要。

4、链接迁移

tcp是有4元组为基础的(客户端ip+port以及服务端的ip+port),但是移动/wifi可能会出现不停的断开而导致ip不停的变换。如何在客户端的ip和port浮动的情况下依旧维持链接?

大家知道,tcp本身就是一个逻辑概念,“假的”。quic也可以创造一个“假的”链接,不用你的4元组了。其过程就是:让客户端生成一个64位的数字标识链接,任你IP+port如何漂移变动,我这个字符串不变,这条连接就会存在。这样对于上层应用来说,链接就一直进行着。

 

添加评论

Loading