专栏首页Node.js开发白话http队头阻塞

白话http队头阻塞

题图 From Bing By clm

http协议的1.0版本与1.1版本最大的一个区别就是http1.1增加了长连接功能,那什么是http的长连接呢?

在了解http的长连接之前,我们来看一下http1.0的请求是如何建立连接的,首先我们要清楚的是,http不论哪个版本,都是建立在tcp协议上的,而tcp的连接需要经历三次握手,tcp的关闭需要四次挥手,而http1.0协议中每个http请求都需要经历三次握手和四次挥手,页面中都多少个http请求,就需要建立多少次握手和挥手,流程如图:

但是在http1.1中新增了长连接功能,这个长连接功能通常被叫做http长连接,笔者认为这个叫法不太准确,应该叫做tcp长连接,为什么这样说呢,因为在http1.1中,如果页面中发起了多个http请求,此时只需要建立一个tcp连接就可以了,多个http请求响应会共用这一个tcp连接通道。

此时http请求中会携带一个Http请求头:Connection:keep-alive,现在大部分的web服务器都默认支持tcp长连接,也就是网页中的请求不携带Connection:keep-alive请求头,默认就是长连接请求,如果不想支持长连接的话,需要显示的添加Connection:closed请求头。

http1.1请求链接过程,如下:

通过对比两张流程图,我们发现,tcp保持长连接大大提高了传输效率,但是这里还是有一个问题,那就是http的对头阻塞问题。

在一般情况下,HTTP遵守“请求-响应”的模式,也就是客户端每次发送一个请求到服务端,服务端返回响应,这种模式很简单,但是有一个致命缺陷那就是页面中有多个请求,每个请求必须等到前一个请求响应之后才能发送,并且当前请求的响应返回之后,当前请求的下一个请求才能发送,流程如下图:

仔细观察上图:在tcp链接中,http请求必须等待前一个请求响应之后,才能发送,后面的依次类推,由此可以看出,如果在一个tcp通道中如果某个http请求的响应因为某个原因没有及时返回,后面的响应会被阻塞,这就是队头阻塞。

为了提高速度和效率,在持久连接的基础上,HTTP1.1进一步地支持在持久连接上使用管道化(pipelining)特性。管道化允许客户端在已发送的请求收到服务端的响应之前发送下一个请求,借此来减少等待时间提高吞吐,如果多个请求能在同一个TCP分节发送的话,还能提高网络利用率,流程如图:

仔细观察上图,我们发现,同一个tcp连接中可以同时发送多个http请求,也就是并发,但是在响应的时候,必须排队响应,谁先到达的谁先响应,相比不支持管道化的http请求确实提高了效率,但是还是有局限性,加入其中某个响应因为某种原因延迟了几秒,后面的响应都会被阻塞,如图:

观察上图红线标识的响应,因为红线标识的响应被阻塞了,它后面的所有响应都会被阻塞,这就是队头阻塞

并且使用HTTP管道化还有一些限制:

1、管道化要求服务端按照请求发送的顺序返回响应(FIFO),原因很简单,HTTP请求和响应并没有序号标识,无法将乱序的响应与请求关联起来。

2、当客户端在支持管道化时需要保持未收到响应的请求,当连接意外中断时,需要重新发送这部分请求。如果这个请求只是从服务器获取数据,那么并不会对资源造成任何影响,而如果是一个提交信息的请求如post请求,那么可能会造成资源多次提交从而改变资源,这是不允许的。而不会对服务器资源产生影响的请求有个专业名词叫做幂等请求。客户端在使用管道化的时候请求方式必须是幂等请求。

我将http不支持管道化与管道化的图放在一起,大家比较一下:

因为HTTP管道化本身可能会导致队头阻塞的问题,以及上面提到的一些限制,现代浏览器默认都关闭了管道化,并且大部分服务器也是默认不支持管道化的

那么如何解决队头阻塞呢?

HTTP 协议建议客户端使用并发长连接,注意这个并发指的是tcp并发连接接。RFC2616 里明确限制每个客户端可以建立两个长连接,这里着重说明一下,客户端建立长连接的个数是针对域名发起的,举例说明,当我们访问a.com网站的时候,客户端与a.com服务器建立的长链接就是2个。

但是一般浏览器会把并发链接数增加到6到8个,谷歌浏览器是6个,也就是页面中如果针对同一个域名有多个http请求,谷歌浏览器会针对这个域名建立6个tcp长连接,在每个长连接里面再去处理http请求,但是这种方案其实对服务器的挑战非常大,有些web优化方案中还会突破6到8的限制,那就是域名切片,因为长连接是针对的同一个域名,那么如果开发人员将资源分布在不同的域名上,那么长连接的数量也是可以被突破的。

假设页面中有100张图片,基于这个案例,咱们用图示将http1.0到http1.1的变迁用三张图来表示一下:

http1.0时代:100个http请求建立100个tcp连接。

http1.1时代,tcp支持了长连接,每个tcp可以处理多个http请求。

前面说过了,tcp的并发数可以通过域名切片来增大,但这样做会增大服务器的连接数,当服务器面对海量请求的话,可能会现问题,那么怎么办呢,这是就需要使用http2协议了。我们下期再聊。

下面我给大家总结一下本篇文章的内容:

1、首先我们厘清了一个概念,那就是http长连接其实指的是tcp长连接。

2、队头阻塞是一种现象,http因为请求-响应模型会有队头阻塞的现象出现,队头阻塞指的是在同一个tcp链接中,如果先发送的http请求如果没有响应的话,后面的http请求也不会响应。

3、解决队头阻塞的第一个方案就是并发长连接,浏览器默认是6-8个长连接,我们可以用域名分片的技术突破这个数值。

4、并发长连接虽然在一定程度上解决了http的队头阻塞,但是会对服务器的性能有较高的要求。

本文分享自微信公众号 - nodejs全栈开发(geekclass),作者:挥刀北上

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 揭秘简单请求与复杂请求

    开发网站时经常会用到跨域资源共享(简称cors,后面使用简称)来解决跨域问题,但是在使用cors的时候,http请求会被划分为两类,简单请求和复杂请求,而这两种...

    挥刀北上
  • 从http规范角度来看xmlhttprequest发送请求

    最近有点怠工,停更好久,今天分享一篇小白文,原生ajax,看标题肯定不同于其他文章的ajax,而是从http规范角度来看xmlhttprequest发送请求。

    挥刀北上
  • 手动实现nodejs代理服务器

    最近看到这样一个题目,根据反向代理服务器的原理用nodejs实现一个代理服务器,要求:

    挥刀北上
  • Spring Boot中通过CORS解决跨域问题

    很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略。 同源策略是由Netscape提出的一个著名的安...

    江南一点雨
  • 看完这篇文章,就不用操心跨域问题啦,答案都在这里!

    以前工作开发中,经常会有这样的问题,前端工程师的前端页面由于跨域问题报错了,来协调后端开发人员解决,后台开发人员还那解释你来看我这边的接口是正常的,应该是你的问...

    前端达人
  • HTTP认知(请求与响应)

     浏览器向服务端发送HTTP请求报文;这条请求报文组成由请求行、请求头、请求体三大部分组成:

    Mirror王宇阳
  • Java File类

    把视频名全部重命名 把E:\java目录下所有以java结尾的绝对路径输出控制台

    黑白格
  • cors跨域探讨

    前端跨域方案很多,jsonp、iframe等等,但是个人觉得,最正宗,最无损的跨域方式还是CORS。 CORS(Cross-origin resource sh...

    用户1394570
  • 爬虫 0030~ requests利刃出鞘

    requests第三方封装的模块,通过简化请求和响应数据的处理,简化繁琐的开发步骤和处理逻辑、统一不同请求的编码风格以及高效的数据处理特性等而风靡于爬虫市场。

    大牧莫邪
  • 跨域请求产生错误的原因及处理方法

    如果你在开发网站时曾经尝试通过框架或是浏览器的 fetch、XHR 请求过外部 API 的话,那么一定遇到过跨域请求,还有那个触目惊心的 CORS 错误信息;今...

    疯狂的技术宅

扫码关注云+社区

领取腾讯云代金券