http在现代保持活力


92

因此,据haproxy作者说,他对http知道一两件事:

当CPU速度慢100倍时,发明了Keep-alive来减少服务器上的CPU使用率。但是,没有说持久连接会消耗大量内存,而除了打开它们的客户端之外,任何人都无法使用。在2009年的今天,CPU的价格非常便宜,而且由于架构或价格的原因,内存仍然限制在几GB。如果一个站点需要保持活动状态,那将是一个真正的问题。高负载站点通常会禁用保持活动状态以支持最大数量的并发客户端。没有保持活动的真正弊端是获取对象的延迟稍有增加。浏览器将非Keepalive站点上的并发连接数量加倍,以弥补这一点。

(来自http://haproxy.1wt.eu/

这符合其他人的经验吗?即没有保持活动状态-现在几乎看不到结果了吗?(对于websockets等,可能值得注意的是-对于响应速度非常快的应用程序,无论保持连接状态如何,连接都会保持“打开”状态)。对于远离服务器的人员来说,效果是否更好?或者在加载页面时是否要从同一主机加载许多工件?(我认为CSS,图像和JS之类的东西越来越多地来自缓存友好的CDN)。

有什么想法吗?

(不知道这是否是serverfault.com的内容,但是除非有人告诉我将其移到那里,否则我不会交叉发布)。


1
值得注意的是,在haproxy文档的其他地方,还以其他更有利的方式提到了keep-alive。我很想听听人们的经验,尤其是在大规模托管方面。
Michael Neale 2010年

“获得设计更好的Web /应用服务器”?:-)具有连续性(如连接)连接处理的较新设计(例如Jetty)从本质上缓解了内存/线程问题。此外,“很少有GB”听起来像是2008/2009服务器术语;-)

3
对我来说听起来像是一团糟。设置新插座所涉及的额外RTT是一个严格的物理限制,该限制通常足够长,以使人类可以检测到,并且无法在已知的物理定律内降低。相反,RAM很便宜,也越来越便宜,闲置套接字没有理由使用超过几KB的内存。
Will Dean 2010年

2
但是有趣的是,这不仅是理论,而是haproxy的作者。我所听到的只是理论和假设。
Michael Neale 2010年

Answers:


141

嘿,因为我是本引文的作者,所以我会回复:-)

大型站点上有两个大问题:并发连接和延迟。并发连接是由需要花很长时间才能下载内容的慢速客户端以及空闲连接状态引起的。那些空闲的连接状态是由连接重用来获取多个对象(称为“保持活动”)引起的,延迟会进一步增加该对象。当客户端离服务器非常近时,它可以充分利用连接并确保它几乎永远不会空闲。但是,当序列结束时,没有人会在意快速关闭通道,并且连接保持打开状态并长时间不使用。这就是为什么许多人建议使用非常低的保持活动超时的原因。在诸如Apache之类的某些服务器上,您可以设置的最低超时时间是一秒钟,而要承受高负载通常太高了:如果您前面有20000个客户端,并且它们平均每秒获取一个对象,则将永久建立这些20000个连接。像Apache这样的通用服务器上的20000个并发连接很大,根据要加载的模块的不同,将需要32到64 GB的RAM,即使添加RAM,也可能不希望更高。实际上,对于20000个客户端,您甚至可能在服务器上看到40000至60000个并发连接,因为如果浏览器要提取许多对象,它们将尝试建立2至3个连接。而且即使添加RAM,也可能不希望更高。实际上,对于20000个客户端,您甚至可能在服务器上看到40000至60000个并发连接,因为如果浏览器要提取许多对象,它们将尝试建立2至3个连接。而且即使添加RAM,也可能不希望更高。实际上,对于20000个客户端,您甚至可能在服务器上看到40000至60000个并发连接,因为如果浏览器要提取许多对象,它们将尝试建立2至3个连接。

如果在每个对象之后关闭连接,则并发连接数将大大减少。实际上,到对象之间的时间,下载对象的平均时间将下降一个因子。如果您需要50毫秒下载一个对象(一个微型照片,一个按钮等),并且如上所述平均每秒下载1个对象,则每个客户端只能有0.05个连接,这只有1000个20000个客户端的并发连接。

现在,建立新连接的时间到了。远程客户端将遇到不愉快的延迟。过去,禁用保持活动状态时,浏览器曾经使用大量并发连接。我记得在MSIE上为4,在Netscape上为8。这确实会使平均每个对象的延迟除以那么多。现在,到处都存在保持活动状态,我们不再看到大量数据了,因为这样做会进一步增加远程服务器上的负载,并且浏览器会保护互联网的基础结构。

这意味着,对于当今的浏览器,很难使非保持活动的服务与保持活动的服务一样快地响应。同样,某些浏览器(例如Opera)使用启发式方法尝试使用流水线。流水线是使用保持活动的有效方法,因为它通过发送多个请求而不等待响应来几乎消除了延迟。我已经在包含100张小照片的页面上进行了尝试,第一次访问的速度大约是不使用keep-alive的速度的两倍,但是下一次访问的速度大约是不使用keep-alive的速度的8倍,因为响应是如此之小,以至于只有延迟(仅“ 304”响应)。

我想说的是,理想情况下,浏览器中应该有一些可调参数,以使它们保持获取的对象之间的连接有效,并在页面完成后立即将其删除。但是不幸的是我们没有看到这一点。

因此,某些需要在前端安装通用服务器(例如Apache)且必须支持大量客户端的站点通常必须禁用保持活动状态。为了迫使浏览器增加连接数量,它们使用多个域名,以便可以并行下载。在大量使用SSL的站点上,这尤其成问题,因为连接设置更高,因为还要进行一次往返。

如今更常见的是,此类站点倾向于安装轻量级前端,例如haproxy或nginx,它们可以轻松处理成千上万的并发连接,它们在客户端启用了keep-alive,并在客户端禁用了keep-alive。 Apache方面。在这一方面,就CPU而言,建立连接的成本几乎为零,并且就时间而言根本不明显。这样一来,就可以提供两全其美的优势:由于保持活动状态而导致的延迟很短,客户端的超时时间非常短,而服务器端的连接数量却很少。每个人都很开心 :-)

一些商业产品通过重用前端负载均衡器和服务器之间的连接,并在它们之上多路复用所有客户端连接,进一步改善了这一点。当服务器靠近LB时,增益不会比以前的解决方案高很多,但是通常需要对应用程序进行调整,以确保不会由于多个用户之间意外共享连接而在用户之间造成会话交叉的风险。从理论上讲,这永远都不会发生。现实大不相同:-)


1
谢谢您的全面答复!我对页面上有关保持活动状态的各种评论感到有些困惑-但这一切都是有道理的。
Michael Neale 2010年

有趣的是-我观察到Linux上的Chrome浏览器在相当长的几秒钟内重新使用了一个保持活动的连接-即打开另一个选项卡所花费的时间-该另一个选项卡使用了不同的主机名,但通过DNS通配符解析到了同一台服务器(质量虚拟主机)-从而重复使用相同的连接!(这给我带来了一些惊喜,而不是很好的选择-显然,如果存活仅是客户端,那很好)。
Michael Neale 2010年

我所听到的只是“使用Apache以外的任何东西,这没什么大不了的”。我的推断是“禁用mod_php和passenger,然后甚至apache也会有战斗的机会”。
coolaj86

@ CoolAJ86:关键是绝对不要抨击Apache,我亲自使用它。关键是服务器越通用,您必须扩展的选项就越少。某些模块需要使用前叉模型,因此您无法扩展到大量连接。但是正如所解释的,这没什么大不了的,因为您可以将其与另一个免费组件(例如haproxy)结合使用。在这种情况下,为什么有人会替换所有东西?最好安装haproxy,而不要使用另一台服务器来重新实现您的应用程序!
威利·塔罗

22

自编写(并在此处发布在stackoverflow上)以来的几年中,我们现在拥有诸如nginx之类的服务器,它们正在日益普及。

例如,nginx只需2.5 MB(兆字节)的RAM即可在单个进程中保持10,000个保持活动连接。实际上,使用很少的RAM来保持打开数以千计的连接很容易,并且您遇到的唯一限制是其他限制,例如打开文件句柄或TCP连接的数量。

保持活动不是问题,不是因为保持活动规范本身存在任何问题,而是由于Apache的基于进程的扩展模型以及被侵入到其架构不适合该服务器的服务器中的保持活动。

尤其有问题的是Apache Prefork + mod_php + keep-alives。在这种模型中,每个连接都将继续占用PHP进程占用的所有RAM,即使它完全处于空闲状态并且仅作为保持活动状态保持打开状态。这是不可扩展的。但是服务器不必以这种方式设计-服务器没有特别的理由需要将每个keep-alive连接保持在单独的进程中(尤其是当每个此类进程都具有完整的PHP解释器时,则不需要这样做)。PHP-FPM和基于事件的服务器处理模型(例如nginx中的模型)很好地解决了该问题。

2015年更新:

SPDY和HTTP / 2用更好的东西替代了HTTP的保持活动功能:不仅保持连接并在其上发出多个请求和响应的能力,而且还可以将它们复用,从而可以按任何顺序发送响应,并且同时进行,而不是仅按请求的顺序进行。这样可以防止较慢的响应阻止较快的响应,并消除了浏览器保持与单个服务器建立多个并行连接的诱惑。这些技术进一步凸显了mod_php方法的不足之处,以及基于事件(至少是多线程)的Web服务器与PHP-FPM之类的结合所带来的好处。


2

我的理解是,它与CPU没有多大关系,但与世界另一端打开重复的套接字有关的延迟。即使您拥有无限带宽,连接延迟也会减慢整个过程。如果您的页面有数十个对象,则放大。即使是持久连接也具有请求/响应延迟,但是平均而言,当您有2个套接字时,连接延迟会减少,一个套接字应该正在传输数据,而另一个套接字可能正在阻塞。同样,路由器在允许您写入之前永远不会假设套接字已连接。它需要完整的往返握手。再次,我没有声称自己是专家,但这就是我一直看到的方式。真正很酷的是完全ASYNC协议(不,不是完全不正常的协议)。


是的-那是我的假设。也许这是一个折衷方案-在某种程度上,延迟(由于距离而定)意味着这是一个真正的问题
Michael Neale 2010年

好的,所以现代印刷术会让您连接到(也许)附近的代理。但是您是否将问题扩展到代理是否应使用持久连接?
catchpolenet 2010年

@Michael Neale也由于TCP慢启动之类的原因,实际的延迟损失比您预期的要差得多。
MartinodF 2010年

也许权衡是一个较短的超时时间。如果您有备份的请求,为什么要关闭套接字并重新启动?即使是1秒,也将允许页面完全持久地加载,然后在此之后立即关闭套接字。
catchpolenet 2010年

2

如果您使用的是CloudFront或CloudFlare之类的“原始拉动” CDN,那么非常长的保持活动可能会很有用。实际上,即使您正在提供完全动态的内容,这也可以比没有CDN更快。

如果您的寿命很长,以至于每个PoP基本上都与您的服务器建立永久连接,那么用户首次访问您的站点时,他们可以与本地PoP进行快速的TCP握手,而不必与您进行缓慢的握手。(光本身需要大约100毫秒才能通过光纤到达世界的一半,建立TCP连接需要来回传递三个数据包 。SSL需要三个往返。)


1
我很想+1,但是您的第二段对光的这种不正确的评论只花了10毫秒就可以在世界中途旅行。真空中10毫秒的光速为3000公里,光纤中10毫秒的光速不超过2000公里;在世界中途(沿水面)为20,000公里。因此,这将是100毫秒-如果您的光纤仅从伦敦直接到达悉尼,而不是可能绕海绕行非洲或经夏威夷走很长一段路……
金字塔

@pyramids你是对的,我打错了字,或者只是愚蠢。将更新。
mjs 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.