现代的http保持活力
Posted
技术标签:
【中文标题】现代的http保持活力【英文标题】:http keep-alive in the modern age 【发布时间】:2011-05-07 13:34:01 【问题描述】:所以根据haproxy作者的说法,谁知道一两件事关于http:
Keep-alive 是为了减少 CPU 而发明的 CPU 为 100 时服务器上的使用情况 慢几倍。但没有说的是 持久连接消耗 大量内存而不可用 由除客户以外的任何人 打开它们。 2009 年的今天,CPU 是 很便宜而且内存还是有限的 到几千兆字节的架构 或价格。如果网站需要 keep-alive,有一个真正的问题。 高负载网站经常禁用 keep-alive 支持最大 同时客户端的数量。这 没有保活的真正缺点 是稍微增加延迟到 获取对象。浏览器翻倍 并发连接数 non-keepalive 网站来弥补 这个。
(来自http://haproxy.1wt.eu/)
这符合其他人的经验吗?即没有keep-alive - 结果现在几乎不明显吗? (可能值得注意的是,使用 websockets 等 - 无论保持活动状态如何,连接都保持“打开” - 对于响应速度非常快的应用程序)。 对于远离服务器的人来说效果是否更大 - 或者在加载页面时要从同一主机加载许多工件? (我认为 CSS、图像和 JS 之类的东西越来越多地来自缓存友好的 CDN)。
想法?
(不确定这是否是 serverfault.com 的问题,但在有人告诉我将其移到那里之前,我不会交叉发布)。
【问题讨论】:
值得注意的是,在 haproxy 的文档中,keep-alive 的其他地方以其他更有利的方式提及。我很想听听人们的经验,尤其是在大规模托管方面。 “获得设计更好的网络/应用程序服务器”? :-) 具有延续(类似)连接处理的较新设计(例如 Jetty)从本质上缓解了内存/线程问题。此外,“几 GB”听起来像是 2008/2009 服务器术语 ;-) 对我来说这听起来像是废话。设置新套接字所涉及的额外 RTT 是一个硬物理限制,该限制通常足够长以至于人类可以检测到,并且不能在已知的物理定律范围内减少。相反,RAM 很便宜,越来越便宜,空闲套接字没有理由使用超过几 kB 的内存。 但有趣的是这不仅仅是理论——这是 haproxy 的作者。我听到的其他一切都是理论和假设。 【参考方案1】:自从撰写本文(并在此处发布在 *** 上)以来的几年中,我们现在拥有越来越受欢迎的 nginx 等服务器。
例如,nginx 可以在一个只有 2.5 MB(兆字节)RAM 的进程中保持打开的 10,000 个保持连接。事实上,用很少的 RAM 保持打开数千个连接很容易,您会遇到的唯一限制是其他限制,例如打开的文件句柄或 TCP 连接的数量。
keep-alive 是一个问题,不是因为 keep-alive 规范本身有任何问题,而是因为 Apache 的基于进程的扩展模型和 keep-alive 侵入了架构无法容纳的服务器它。
特别有问题的是 Apache Prefork + mod_php + keep-alives。这是一个模型,其中每个连接都将继续占用 PHP 进程占用的所有 RAM,即使它完全空闲并且仅作为保持活动状态保持打开状态。这是不可扩展的。但是服务器不必这样设计——没有特别的理由服务器需要将每个保持活动连接保持在一个单独的进程中(尤其是当每个这样的进程都有一个完整的 PHP 解释器时)。 PHP-FPM 和 nginx 等基于事件的服务器处理模型优雅地解决了这个问题。
2015 年更新:
SPDY 和 HTTP/2 用更好的东西取代了 HTTP 的保持活动功能:不仅能够保持连接并在其上发出多个请求和响应,而且可以多路复用,因此可以发送响应以任何顺序,并行,而不仅仅是按照他们被请求的顺序。这可以防止缓慢的响应阻塞更快的响应,并消除浏览器保持打开多个并行连接到单个服务器的诱惑。这些技术进一步突出了 mod_php 方法的不足之处,以及基于事件(或至少是多线程)的 Web 服务器与 PHP-FPM 之类的东西分开耦合的好处。
【讨论】:
【参考方案2】:如果您使用 CloudFront 或 CloudFlare 等“来源拉取”CDN,那么非常长的保活会很有用。事实上,这比没有 CDN 更快,即使您提供的是完全动态的内容。
如果您长期保持活动状态,以至于每个 PoP 基本上都与您的服务器建立了永久连接,那么当用户第一次访问您的站点时,他们可以与本地 PoP 进行快速 TCP 握手,而不是与您进行慢速握手。 (光本身通过光纤绕半个地球大约需要 100 毫秒,而建立 TCP 连接需要来回传递三个数据包。SSL requires three round-trips。)
【讨论】:
我很想 +1,但是你的第二段有这个错误的评论,光只需要 10 毫秒就可以绕半个地球。真空中 10 毫秒的光速是 3000 公里,光纤中 10 毫秒的光速不超过 2000 公里;地球的中途(沿地表)为 20,000 公里。所以这将是 100 毫秒——如果你的光纤直接从伦敦到悉尼,而不是可能通过海上环游非洲或通过夏威夷走长途...... @pyramids 你说得对,要么是我打错了,要么就是搞砸了。会更新。 从澳大利亚墨尔本或悉尼到美国西海岸(洛杉矶)的往返行程最短约 160 毫秒,即单程约 80 毫秒。考虑到它似乎与理论上的最佳情况非常接近,这非常好。【参考方案3】:嘿,既然我是这篇引文的作者,我会回应:-)
大型网站存在两个大问题:并发连接和延迟。并发连接是由下载内容需要很长时间的慢速客户端和空闲连接状态引起的。这些空闲连接状态是由连接重用以获取多个对象引起的,称为保持活动状态,延迟会进一步增加。当客户端非常靠近服务器时,它可以密集使用连接并确保它几乎从不空闲。然而,当序列结束时,没有人关心快速关闭通道,并且连接长时间保持打开和未使用状态。这就是为什么许多人建议使用非常低的保持活动超时的原因。在某些服务器(如 Apache)上,您可以设置的最低超时时间是一秒,这对于维持高负载来说通常太多了:如果您面前有 20000 个客户端并且它们平均每秒获取一个对象,您将永久建立这 20000 个连接。像 Apache 这样的通用服务器上的 20000 个并发连接是巨大的,需要 32 到 64 GB 的 RAM,具体取决于加载的模块,即使添加 RAM,您也可能不希望更高。实际上,对于 20000 个客户端,您甚至可能会在服务器上看到 40000 到 60000 个并发连接,因为如果浏览器要获取许多对象,它们会尝试建立 2 到 3 个连接。
如果在每个对象之后关闭连接,并发连接数将急剧下降。实际上,它将下降一个因子,该因子对应于对象之间的时间下载对象的平均时间。如果您需要 50 毫秒来下载一个对象(一张微型照片、一个按钮等...),并且如上所述平均每秒下载 1 个对象,那么每个客户端只有 0.05 个连接,即只有 1000 个20000 个客户端的并发连接。
现在是时候建立新的连接了。远程客户端将经历令人不快的延迟。过去,浏览器在禁用 keep-alive 时会使用大量并发连接。我记得在 MSIE 上是 4,在 Netscape 上是 8。这实际上会将每个对象的平均延迟除以那么多。现在keep-alive无处不在,我们再也看不到这么高的数字了,因为这样做会进一步增加远程服务器的负载,而浏览器负责保护互联网的基础设施。
这意味着在当今的浏览器中,让非保活服务与保活服务一样具有响应性变得更加困难。此外,一些浏览器(例如:Opera)使用启发式方法来尝试使用流水线。流水线是使用 keep-alive 的一种有效方式,因为它通过发送多个请求而不等待响应几乎消除了延迟。我在一个有 100 张小照片的页面上尝试过,第一次访问的速度大约是没有 keep-alive 的两倍,但下一次访问的速度大约是 8 倍,因为响应非常小,只计算延迟(仅“304”响应)。
我想说理想情况下,我们应该在浏览器中设置一些可调参数,以使它们在获取的对象之间保持连接,并在页面完成时立即删除它。但不幸的是,我们没有看到。
出于这个原因,一些需要在前端安装通用服务器(例如 Apache)并且必须支持大量客户端的站点通常必须禁用 keep-alive。并且为了强制浏览器增加连接数,它们使用多个域名,以便可以并行下载。这在大量使用 SSL 的网站上尤其成问题,因为连接设置甚至更高,因为有一个额外的往返。
现在比较常见的是,这类网站更喜欢安装轻量级前端,比如 haproxy 或 nginx,处理几万到几十万并发连接没有问题,它们在客户端启用 keep-alive,并禁用它在 Apache 端。在这方面,建立连接的成本在 CPU 方面几乎为零,在时间方面根本不明显。这样一来,这提供了两全其美:由于保持活动状态而导致的低延迟,客户端的超时非常低,而服务器端的连接数也很少。每个人都很高兴:-)
一些商业产品通过重用前端负载平衡器和服务器之间的连接并通过它们多路复用所有客户端连接来进一步改进这一点。当服务器靠近 LB 时,增益不会比以前的方案高多少,但通常需要对应用程序进行适配,以确保不会因多个用户之间意外共享连接而导致用户之间会话交叉的风险.理论上这不应该发生。现实大不相同:-)
【讨论】:
感谢您完整而全面的回答!我对页面上关于 keep-alive 的各种 cmet 感到有些困惑 - 但这一切都是有道理的。 有趣的是——我观察到 linux 上的 Chrome 在几秒钟内重复使用保持活动连接——即打开另一个选项卡所花费的时间——另一个选项卡指向不同的主机名,但通过DNS通配符到同一台服务器(大量虚拟主机) - 从而重用相同的连接! (这让我有些吃惊,不是很好——显然,如果保持活动只是客户端就可以了)。 我听到的只是“使用 apache 以外的任何东西,这没什么大不了的”。我推断的是“禁用 mod_php 和乘客,然后甚至 apache 也可能有机会”。 @CoolAJ86:重点绝对不是 bash Apache,我个人使用它。关键是服务器越通用,您必须扩展的选项就越少。某些模块需要 pre-fork 模型,然后您无法扩展到大量连接。但正如解释的那样,这没什么大不了的,因为您可以将它与另一个免费组件(如 haproxy)结合使用。在这种情况下,为什么有人会替换所有东西?最好安装 haproxy,而不是使用另一台服务器重新实现您的应用程序!【参考方案4】:我的理解是它与 CPU 无关,而是打开重复套接字到世界另一端的延迟。即使您有无限带宽,连接延迟也会减慢整个过程。如果您的页面有几十个对象,则放大。即使是持久连接也有请求/响应延迟,但是当你有 2 个套接字时它会减少,因为平均而言,一个应该是流数据,而另一个可能是阻塞的。此外,在让您写入之前,路由器永远不会假设套接字已连接。它需要完整的往返握手。再说一次,我不声称自己是专家,但这就是我一直以来的看法。真正很酷的是完全 ASYNC 协议(不,不是完全病态的协议)。
【讨论】:
是的 - 这是我的假设。也许这是一个权衡 - 有一点延迟(由于距离)意味着这是一个真正的问题 好的,所以现代排版会让你连接到附近的代理(也许)。但是您是否将问题扩展到代理是否应该使用持久连接? @Michael Neale 同样,由于 TCP 启动缓慢等原因,实际延迟损失比您预期的要严重得多。 也许权衡的是更短的超时时间。如果您备份了请求,为什么要关闭套接字并重新启动?即使是 1 秒,页面也可以完全持久加载,然后立即关闭套接字。以上是关于现代的http保持活力的主要内容,如果未能解决你的问题,请参考以下文章