ChatGPT解决这个技术问题 Extra ChatGPT

现代的http保持活力

所以根据haproxy作者,谁知道一两件事关于http:

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

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

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

想法?

(不确定这是否是 serverfault.com 的问题,但在有人告诉我把它移到那里之前,我不会交叉发布)。

值得注意的是,在 haproxy 的文档中,keep-alive 的其他地方以其他更有利的术语提及。我很想听听人们的经验,尤其是对于大规模托管。
“获得设计更好的 Web/应用程序服务器”? :-) 具有延续(类似)连接处理的较新设计(例如 Jetty)从本质上缓解了内存/线程问题。此外,“几 GB”听起来像是 2008/2009 服务器术语;-)
对我来说这听起来像是胡说八道。设置新套接字所涉及的额外 RTT 是一个硬物理限制,该限制通常足够长,足以被人类检测到,并且无法在已知的物理定律范围内减少。相反,RAM 很便宜,越来越便宜,空闲套接字没有理由使用超过几 kB 的内存。
但有趣的是,这不仅仅是理论——这是 haproxy 的作者。我听到的其他一切都是理论和假设。

W
Willy Tarreau

嘿,因为我是这篇引文的作者,我会回应:-)

大型站点存在两个大问题:并发连接和延迟。并发连接是由下载内容需要很长时间的慢速客户端和空闲连接状态引起的。这些空闲连接状态是由连接重用以获取多个对象引起的,称为保持活动状态,延迟会进一步增加。当客户端非常靠近服务器时,它可以密集使用连接并确保它几乎从不空闲。然而,当序列结束时,没有人关心快速关闭通道,并且连接长时间保持打开和未使用状态。这就是为什么许多人建议使用非常低的保持活动超时的原因。在像 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,在客户端禁用它阿帕奇方面。在这方面,建立连接的成本在 CPU 方面几乎为零,在时间方面根本不明显。这样一来,这提供了两全其美的效果:由于保持活动的低延迟,客户端的超时非常低,服务器端的连接数量少。大家都开心 :-)

一些商业产品通过重用前端负载均衡器和服务器之间的连接并在它们上多路复用所有客户端连接来进一步改进这一点。当服务器靠近 LB 时,增益不会比以前的方案高多少,但通常需要对应用程序进行适配,以确保不会因多个用户之间意外共享连接而导致用户之间会话交叉的风险.理论上这不应该发生。现实有很大不同:-)


感谢您完整而全面的回答!我对页面上关于 keep-alive 的各种评论感到有些困惑——但这一切都是有道理的。
有趣的是 - 我观察到 Linux 上的 Chrome 在几秒钟内重复使用保持活动连接 - 即打开另一个选项卡所花费的时间 - 这个另一个选项卡是不同的主机名,但通过 DNS 通配符解析到同一台服务器(质量虚拟主机) - 从而重用相同的连接! (这让我有些惊讶,而不是好的那种——显然,如果保持活力只是客户端,那很好)。
我所听到的只是“使用 apache 以外的任何东西,这没什么大不了的”。我推断的是“禁用 mod_php 和乘客,然后甚至 apache 也可能有战斗的机会”。
@CoolAJ86:重点绝对不是 bash Apache,我个人确实使用它。关键是服务器越通用,您必须扩展的选项就越少。某些模块需要 pre-fork 模型,然后您无法扩展到大量连接。但正如解释的那样,这没什么大不了的,因为您可以将它与另一个免费组件(如 haproxy)结合使用。为什么有人会在这种情况下更换所有东西?最好安装 haproxy,而不是使用另一台服务器重新实现应用程序的麻烦!
C
Community

自从写这篇文章(并在 stackoverflow 上发布)以来的几年里,我们现在拥有像 nginx 这样的服务器,它们越来越受欢迎。

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

Keep-alive 是一个问题,不是因为 keep-alive 规范本身有任何问题,而是因为 Apache 的基于进程的扩展模型和 keep-alives 侵入了架构不是为适应它而设计的服务器。

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

2015 年更新:

SPDY 和 HTTP/2 用更好的东西取代了 HTTP 的 keep-alive 功能:不仅可以保持连接并在其上发出多个请求和响应,而且可以多路复用,因此可以以任何顺序发送响应,并且是并行的,而不仅仅是按照请求的顺序。这可以防止缓慢的响应阻塞更快的响应,并消除浏览器保持打开多个并行连接到单个服务器的诱惑。这些技术进一步突出了 mod_php 方法的不足之处,以及基于事件(或至少是多线程)的 Web 服务器与 PHP-FPM 之类的东西分开耦合的好处。


c
catchpolenet

我的理解是,它与 CPU 无关,而是打开重复套接字到世界另一端的延迟。即使您有无限带宽,连接延迟也会减慢整个过程。如果您的页面有几十个对象,则放大。即使是持久连接也有请求/响应延迟,但是当您有 2 个套接字时它会减少,因为平均而言,一个应该是流数据,而另一个可能是阻塞的。此外,在让您写入之前,路由器永远不会假设套接字已连接。它需要完整的往返握手。再说一次,我不声称自己是专家,但这就是我一直以来的看法。真正酷的是一个完全异步的协议(不,不是一个完全病态的协议)。


是的 - 那将是我的假设。也许这是一个权衡 - 有一点延迟(由于距离)意味着这是一个真正的问题
好的,所以现代排版会让你连接到附近的代理(也许)。但是您是否将问题扩展到代理是否应该使用持久连接?
@Michael Neale 同样,由于 TCP 启动缓慢等原因,实际延迟损失比您预期的要严重得多。
也许权衡是更短的超时时间。如果您备份了请求,为什么要关闭套接字并重新启动?即使是 1 秒,页面也可以完全持久地加载,然后立即关闭套接字。
m
mjs

如果您使用 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 毫秒。考虑到它似乎与理论上的最佳情况非常接近,这非常好。