HTTP/1.1队首阻塞和HTTP/2优化

应用层的优化的方式很多,我知道的有浏览器上的优化,通常我们浏览一个HTML网页时,客户端向服务器端发送请求得到主页面,主页面上由很多元素组成,JS文件,CSS样式文件和各种音频图片等资源,等待服务器端发送HTTP或HTTPS响应,在接收到主页面响应后,开始进行页面布局,即构建DOM文档对象模型。页面构建完成后,客户端浏览器继续发送请求,获取页面上的子元素(CSS文件,图片音频等)进行页面渲染。由于一个页面上通常有多个子元素组成,所以客户端浏览器需要发送很多个请求来获取这些子元素,为了提高效率,HTTP/1.1版本上使用了一种管道技术来并行发送和处理多个请求。

 

HTTP/1.1管道技术

在HTTP/1.1版本上使用了一种叫Pipelining管道技术的方式,让客户端能够并行发送多个请求,服务器端也可以并行处理多个来自客户端的请求。在一个TCP连接中,发送多个HTTP请求,不需要等待服务器端对前一个请求的响应之后,再发送下一个请求。但是使用了管道技术的HTTP/1.1,根据HTTP/1.1的规则,服务器端在响应时,要严格按照接收请求的顺序发送,即先接收到的请求,需要先发送其响应,客户端浏览器也是如此,接收响应的顺序要按照自己发送请求的顺序来。举个例子,ajax请求,在客户端发送多个ajax请求,希望获得HTML页面中某一个元素,如果不按照发送请求的顺序来接收响应,第一个ajax请求响应时间因为时间长,而将后面的响应数据覆盖掉,页面数据显示混乱。

HTTP/1.1队首阻塞和HTTP/2优化

 

队首阻塞问题

总的来说,管道技术允许客户端和服务器端并行发送多个请求和响应,但是客户端接收响应的顺序要和自己发送请求的顺序对应,服务器端发送响应的顺序要和自己接收到的请求的顺序对应,这样做似乎没什么问题,看起来是不是“FIFO”先来先服务的方式,如果前面收到的一个请求,在服务器端处理的时间很长,生成响应需要很多时间,那么对于后面的已经处理完生成响应的请求来说,它们只能阻塞等待,等待前面的响应发送完后,自己才能被发送出去(即使该请求的响应已经生成),造成了“队首阻塞”问题。可见队首阻塞发生在服务器端,虽然服务器端并行接收了多个请求,也并行处理生成多个响应,但由于要遵守HTTP/1.1的规则,先接收到的请求需要先发送响应,造成了阻塞问题。

可能你会想到,一个TCP连接上发送请求和接收响应,由于HTTP/1.1的缘故会造成队首阻塞,那么一次建立多个TCP连接,不就可以一次下载更多的子元素,更快渲染出HTML页面。没错,建立多个TCP连接的确可以对上面的问题进行优化,但是建立多个TCP连接是十分耗费客户端和服务器端的资源的,每建立一个连接需要三次握手,1.5次RTT,在连接建立完后,长连接(或者叫连接复用)使得请求和响应完成后,连接不会立刻关闭,即使后面没有请求发送,服务器也必须维持着这么一些TCP连接,耗费不少服务器的资源。所以多个TCP连接的优化方式缺陷还是挺大的,最主要是耗费客户端和服务器端的资源。

      在HTTP/2里经过更好的改进和设计,解决了HTTP/1.1队首阻塞问题,其中总结了二进制分帧和并行处理方面,看看HTTP/2做了哪些优化工作。

 

HTTP/2优化

HTTP/2支持在一个TCP连接中并行发送多个请求和接收多个响应,无需等待,因为对HTTP消息进行二进制分帧的方式进行编码,客户端和服务器端之间的消息传递变成互不干扰的帧,可以交错发送,待接收完之后再组装成完整的消息。由此可见,在HTTP/2上客户端接收响应无需严格按照发送请求的顺序,服务器端发送响应也无需严格按照接收到请求的顺序,只要当前TCP连接可用,双方就可以互相发送消息。

二进制分帧

       与HTTP/1.1不同,HTTP/2将发送的消息由文本形式转换成了二进制数据流方式,也就是编码方式发生了改变。HTTP/2将消息帧编码成二进制格式,一条消息被拆分成多个帧,帧是最小的通信单位,

每个帧都有编号,这些二进制帧数据流到达另一端后再根据帧的编号进行组装。帧在客户端和服务器端的TCP连接上是双向传输的,以字节流的方式,互不干扰(因为编码和封装方式),可以交错发送,只要当前TCP连接可用,就可以发送请求和响应,消除了HTTP/1.1中请求和响应对应的关系,HTTP/1.1中一个TCP连接要严格按照顺序发送请求和接收响应,如果一个响应没有发送出去,那么后面的响应即使生成完毕,也必须等待。使用了HTTP/2进行通信,二进制分帧的方式使得请求和响应都是以数据流的方式并行发送,客户端和服务器端接收到数据流后,再根据帧的编号进行组装,得到完整的消息,以此解决队首阻塞问题。

并行处理

二进制分帧的方式还有一个好处就是能实现一个TCP连接的请求和响应复用,在一个连接上,客户端浏览器和服务器端可以不断向对方发送帧,一个请求或响应就是一个数据流,在每个流中交错发送帧给对方,即实现了并行处理。上面队首阻塞中的一个问题(或者说优化方案)是建立多个TCP连接来提升并行处理的能力,但是这种方式的缺点很明显,长连接的方式使得一直保持着多个TCP连接,会耗费客户端和服务器端的不少资源。在HTTP/2下将消息拆分成多个帧,以二进制编码交错发送,当客户端浏览器向服务器端发送数据流(一系列的帧)时,服务器也可以同时发送自己已生成的响应数据流,无需像HTTP/1.1那样请求与响应匹配,实现了并行发送多个交错请求和响应,之间互不干扰,并行处理,且只需在一个TCP连接上,减少资源负担。

到这里我已经把自己知道的HTTPS性能优化都总结了,上一篇日志是在网络层的优化,例如流量控制,启用慢启动。应用层优化的地方就很多了,长连接,多个TCP连接,队首阻塞问题和多个TCP连接耗费资源问题都在HTTP/2里得到解决,二进制分帧也提供了更好的并行处理。