keep-alive是持久连接,以消除连接和关闭时延。在详细介绍持久连接之前我们先来看看其他的几种连接方式。
串行连接
如果只对事务(本文中的事务是指http事务,即一个req/res对)进行简单的处理,也就是串行处理http事务,TCP的性能时延可能会叠加起来(TCP连接有握手时延,延迟确认,慢启动等问题)。此时一个http连接对应一个tcp连接,就会造成我们对资源的大量浪费。
示意图
假设我们要在一个web界面里面发起 AJAX 三次请求。浏览器则需要发起四个http事务来显示此界面。第一个是对整个界面的请求,接下来三个是三次AJAX请求。串行连接的示意图如下所示:
缺点
-
浏览器在加载时逐个加载,带给用户刷新速率较慢的感觉。
-
如果加载的是响应式图片,单个图片加载完成后无法确定图片的尺寸,用户此时需要面对的是一扇空白的屏幕。
并行连接
通过多条TCP连接发起的HTTP请求。
通过这种方式我们可以通过HTTP允许客户端打开多条连接,每个TCP连接单独处理单个HTTP事务。
示意图
首先加载整个HTML界面,然后并行处理其他三个事务。
通常每个连接之间都会有一小段软件时延。
But 并行连接不一定快哦
如果并行加载多个对象,每个对象都会去竞争这有限的带宽,每个对象都会以较慢的速度按比例加载,这样带来的性能的提升就会很小,甚至没有什么提升。
而且,打开大量的连接会消耗很多资源,从而引发自身的性能问题。eg:一个界面需要建立100个连接才能完成客户的需求,如果同事一百个用户同时请求,服务器将会在一瞬间承载10000个连接,这样一来服务器真地快的起来吗?
但是并行连接会让用户觉得好像快了一些。实际上并行连接并不一定不会加快页面的传输速度(因为多条连接会产生额外的开销,使用并行连接装载整个界面需要的开销可能比串行条件下需要的时间更长),用户感觉更快了是因为多个组件对象可以同时将加载的进度显示在屏幕上,用户同一时间看到了多个对象的进度的加载。
并行连接的缺点:
- 每个事务都会打开/关闭一条新的连接,会耗费时间的和带宽。
- 由于TCP慢启动特性的存在,每条新连接的性能都会有所降低。
- 可打开的并行连接的数量实际上是有限的(socket端口是有限的)。
持久连接
描Web客户端经常会打开一个到持久站点的连接。比如,一个web界面上的大部分内嵌图片都来自同一个Web站点,而且相当一部分指向其他对象的连接也来自于相同的Web站点。因此初始化了对某服务器HTTP请求的应用程序很可能会在不久的将来对那台服务器发起更多地请求。这种性质被称为站点局部性。
为了应对这种情况,HTTP允许用户在事务处理结束之后将TCP连接保持在打开状态,以便为未来的HTTP请求重现现存的连接。在事务处理之后仍然保持在打开连接状态的TCP连接称为持久连接。非持久连接,会在每个事务结束之后关闭。持久连接会在不同事务之间保持打开状态,直到客户端或服务器决定将其关闭为止。
重用已对目标服务器打开的空闲持久连接,就可以避开缓慢的连接建立阶段。而且,已经打开的连接还可以避免慢启动的拥塞适应阶段。
持久连接有一些比并行连接更好的地方,持久连接降低了时延和连接建立的开销,一直保持连接。但是管理连接的时候要特别小心,不然会积累出来大量的空闲连接,对服务器资源是一种浪费。
目前持久连接和并行连接配合可能是最有效的方式。现在,很多Web连接都是打开少量的并行连接,其中的每一个都是持久连接。
示意图
持久连接类型 1 keep-alive
keep-alive已经不在使用了,但是浏览器和服务器对keep-alive的我收仍然十分广泛,因此http的实现者应该做好与之交互的准备。
实现keep-alive的客户端可以通过包含Connection: keep-alive首部请求将一条连接保持打开状态。如果服务器愿意为下一条连接保持打开状态,就在响应中包含相同的首部。如果响应中没有Connection: keep-alive首部,客户端就认为服务器不支持keep-alive,会在发送响应报文后关闭连接。
正常建立了持久连接之后也可以通过参数限制持久连接的行为。
- 参数timeout估计了服务器希望将连接保持在活跃状态的时间。
- 参数max估计了服务器还希望为多少个连接提供服务。
- keep-alive还支持未经处理的属性,这些属性主要用于诊断和调试。
Connetction: Keep-Alive
Keep-Alive: max=5, timeout=120
限制和规则
- 发送了Connection: close之后,客户端就无法在那条连接上发送更多的请求了。
- 如果客户端不想在连接上发送其他的请求,就应该在最后一条请求中发送Connection: close选项。
- 怎样判断一个长连接中的一个事务的范围呢?
HTTP协议中客户端发送一个小请求,服务器响应以所期望的信息(例如一个html文件或一副gif图像)。服务器通常在发送回所请求的数据之后就关闭连接。这样客户端读数据时会返回EOF(-1),就知道数据已经接收完全了。在http持久连接中,我们通过content-length或者chunk传输编码的方式来划分一个事务的范围
想要了解content-length和chunk的规则,可以参考这篇文章----用了这么久HTTP, 你是否了解Content-Length和Transfer-Encoding ?
- 尽管服务器不应该试图在传输报文的过程中关闭连接,而且在关闭连接之前至少应该有一条响应告知客户端,但是事实上不管Connection取了什么值,HTTP1.1设备都可以在任意时刻关闭连接。
写在文章后
TCP连接也有自己的keepalive选项,但是他的keepalive和http的keep-alive是不一样的。具体可以参考文章TCP Keepalive HOWTO