![]() |
1
140
嘿,既然我是这篇引文的作者,我会回答:-) 在大型站点上有两个大问题:并发连接和延迟。并发连接是由下载内容需要很长时间的慢速客户端和空闲连接状态引起的。这些空闲连接状态是由于连接重用来获取多个对象(称为keep alive)而导致的,而延迟会进一步增加这些对象。当客户机非常靠近服务器时,它可以充分利用连接,并确保它几乎从不空闲。但是,当序列结束时,没有人关心是否要快速关闭通道,并且连接将保持打开和长时间未使用。这就是为什么很多人建议使用一个非常低的生存超时。在像Apache这样的服务器上,您可以设置的最低超时时间是1秒,而且对于维持高负载来说通常太多了:如果您前面有20000个客户机,并且他们平均每秒获取一个对象,那么您将永久建立这20000个连接。在像Apache这样的通用服务器上,20000个并发连接是巨大的,需要32到64gb的RAM,这取决于加载了哪些模块,您可能不希望通过添加RAM来达到更高的要求。实际上,对于20000个客户机,您甚至可能在服务器上看到40000到60000个并发连接,因为如果浏览器有许多对象要获取,它们将尝试设置2到3个连接。 如果在每个对象之后关闭连接,则并发连接的数量将显著减少。实际上,它会下降一个因子,这个因子对应于按对象之间的时间下载对象的平均时间。如果您需要50毫秒来下载一个对象(一张微型照片、一个按钮等等),并且您平均每秒下载1个对象,那么每个客户机只有0.05个连接,这对于20000个客户机来说只有1000个并发连接。 现在,建立新的联系的时间就要开始了。远程客户端将经历不愉快的延迟。在过去,当keep alive被禁用时,浏览器使用大量并发连接。我记得MSIE上有4个,Netscape上有8个。这真的可以将每个对象的平均延迟除以这么多。既然keep alive无处不在,我们再也看不到这么高的数字了,因为这样做会进一步增加远程服务器的负载,浏览器会保护互联网的基础设施。 这意味着,在当今的浏览器中,要让非保持活动状态的服务像保持活动状态的服务一样具有响应性是很困难的。另外,一些浏览器(如Opera)使用启发式来尝试使用流水线。流水线是使用keep alive的一种有效方法,因为它几乎通过发送多个请求而不等待响应来消除延迟。我在一个有100张小照片的页面上尝试过,第一次访问的速度大约是不保持活动状态的两倍,但下一次访问的速度大约是8倍,因为响应太小,所以只有延迟计数(只有“304”个响应)。 我想说,理想情况下,我们应该在浏览器中使用一些可调参数,使它们保持获取的对象之间的连接,并在页面完成时立即删除它。但不幸的是我们没有看到。 因此,一些需要在前端安装通用服务器(如Apache)并且必须支持大量客户端的站点通常必须禁用keep alive。为了迫使浏览器增加连接数量,他们使用多个域名,这样下载就可以并行化。在大量使用SSL的站点上尤其有问题,因为连接设置甚至更高,因为还有一个额外的往返行程。 现在更常见的现象是,这些站点更喜欢安装轻量级前端,如haproxy或nginx,它们在处理数万到数十万个并发连接时没有问题,它们在客户端启用keep alive,在Apache端禁用它。在这方面,就CPU而言,建立连接的成本几乎为零,而就时间而言,根本不明显。这样,这就提供了两个方面的好处:低延迟,因为在客户端保持活动,超时非常低,而在服务器端连接数很低。每个人都很快乐:-) 一些商业产品通过重新使用前负载均衡器和服务器之间的连接,并通过它们复用所有客户端连接来进一步改进这一点。当服务器接近LB时,增益不会比以前的解决方案高得多,但通常需要对应用程序进行调整,以确保不会由于多个用户之间意外共享连接而导致用户之间的会话交叉。从理论上讲,这不应该发生。现实大不相同 |
![]() |
2
22
在写这篇文章(并在stackoverflow上发布)的几年里,我们现在有了nginx这样的服务器,这些服务器正变得越来越流行。 例如,nginx可以在一个只有2.5MB(兆字节)内存的进程中保持10000个保持活动连接。事实上,用很少的RAM就可以轻松地保持打开数千个连接,而您将遇到的唯一限制是其他限制,如打开的文件句柄数或TCP连接数。 Keep alive不是因为Keep alive规范本身的任何问题,而是因为Apache基于进程的扩展模型,Keep alive s被黑客侵入了一个服务器,该服务器的体系结构不是为适应它而设计的。
2015年更新:
|
|
3
2
我的理解是,这与CPU没什么关系,而是在世界的另一边打开重复的套接字的延迟。即使您拥有无限带宽,连接延迟也会减慢整个过程。如果你的页面有几十个对象,就会放大。即使一个持久连接也有一个请求/响应延迟,但当平均有两个套接字时,它的延迟也会减少,一个套接字应该是流式数据,而另一个套接字可能是阻塞的。而且,路由器在允许您写入数据之前永远不会假设套接字连接。它需要全程往返握手。再说一次,我不自称是专家,但这是我一直看到的。真正酷的是一个完全异步的协议(不,不是完全病态的协议)。 |
![]() |
4
2
如果您使用诸如CloudFront或CloudFlare之类的“origin pull”CDN,那么非常长的keep alives可能会很有用。事实上,即使您提供的是完全动态的内容,这也比没有CDN快。 |