服务器可扩展性 - HTML 5 WebSockets vs Comet

28

许多像Caplin这样的Comet实现提供可扩展的服务器解决方案。

以下是来自Caplin网站的其中一项统计数据:

单个Caplin Liberator实例可以支持多达100,000个客户端,每个客户端每秒接收1条消息,并且平均延迟小于7ms。

与任何Web服务器上的HTML5 WebSocket相比如何?有人可以向我指出任何HTML 5 WebSocket的统计数据吗?


1
关于“HTML 5 WebSockets vs Comet”的评论:正如其他评论所述,Caplin的Liberator以及许多其他“Comet”服务器都支持WebSockets作为连接机制。当服务器不再是Comet服务器时会发生什么?如果它使用WebSockets,它是否仍然是Comet服务器?Comet是HTTP-Long Polling和HTTP Streaming的总称吗?我建议阅读“The Rumours of Comet’s Death Have Been Greatly Exaggerated”。(http://blog.caplin.com/2009/12/17/the-rumours-of-comets-death-have-been-greatly-exaggerated/)。 - leggetter
1
我现在会将此内容保留为注释。但是你真的应该考虑使用EventSource(又名服务器发送事件)作为一个选项。因为它是单向的(只推送),所以它使得扩展到多个服务器变得更加容易。 - igorw
4个回答

42

声明 - 我在Caplin工作。

这个页面上有一些错误信息,所以我想尝试让它更清晰明了。

我认为我们可以将我们谈论的方法分为三类..

  1. Comet HTTP轮询 - 包括长轮询
  2. Comet HTTP流 - 服务器到客户端的消息使用单个持久套接字,除了初始设置后没有HTTP头开销
  3. Comet WebSocket - 单个双向套接字

我把它们都看作是Comet,因为Comet只是一种范式,但自从WebSocket出现以来,一些人想将其视为不同或替代Comet-但它只是另一种技术-除非你满意仅支持最新的浏览器,否则不能仅依赖WebSocket。

就性能而言,大多数基准测试集中在服务器到客户端的消息上-用户数量,每秒消息数量以及这些消息的延迟。对于这种情况,HTTP流和WebSocket之间没有根本性的区别-两者都是通过打开的套接字写入消息,几乎没有标题或开销。

如果消息的频率较低,则长轮询可以提供良好的延迟。但是,如果您有两条消息(从服务器到客户端)接连不断,则第二条消息将在第一条消息接收后进行新请求之前不会到达客户端。

我认为有人触及了HTTP KeepAlive。这显然可以改善长轮询-您仍然需要往返和标题的开销,但不总是需要套接字创建。

在客户端与服务器之间有更多的信息交互时,WebSocket应该比HTTP流式传输更为出色。将这些情景和实际世界联系起来会产生稍微更加任意的设置,与简单易懂的“向许多客户端发送大量消息”的场景相比,每个人都能理解。例如,在交易应用程序中,创建包含执行交易的用户(即客户端到服务器消息)的情境很容易,但结果比基本的服务器到客户端情境要少一些意义。交易者并不试图每秒进行100次交易,因此最终结果可能是“1万个用户每秒接收100条消息,同时每隔5分钟发送一次客户端消息”。对于客户端到服务器消息,更有趣的部分是延迟,因为所需的消息数量通常与服务器到客户端消息相比微不足道。

另外,有人提到了64k个客户端的问题。您不需要做任何聪明的事情来支持超过64k个套接字/sockets的服务器,除了配置文件描述符等数字。如果您试图从单个客户机上建立64k个连接,则完全不同,因为它们需要一个端口号 - 在服务器端这是可以的,那是监听端,您可以轻松处理超过64k个套接字/sockets。


+1,这正是我在之前评论中所提到的。HTTP流和WebSockets的实现在功能上是相同的,但您会失去WebSockets的全双工能力。长轮询和短轮询与WebSockets并不是真正公平的比较,因为连接会不断重新初始化。 - David Titarenco

8
在理论上,WebSockets比HTTP更具可扩展性,但是有一些注意事项和一些方法来解决这些注意事项。
HTTP与WebSockets的握手头处理的复杂性大致相同。HTTP(和初始WebSocket)握手可以很容易地超过1K的数据(由于cookie等)。重要的区别在于,HTTP握手在每个消息中都会再次发生。一旦建立了WebSocket连接,每个消息的开销仅为2-14字节。
@David Titarenco的答案中发布的优秀Jetty基准测试链接(12)显示,与Comet相比,WebSockets可以轻松实现超过一个数量级的更好的延迟。

有关 WebSockets 与 HTTP 的扩展性比较,请参见 this answer

注意事项:

  • WebSocket 连接是长期存在的,不像 HTTP 连接是短期存在的。这显著降低了开销(无需为每个请求/响应创建和管理套接字),但这意味着要将服务器扩展到64k个独立同时客户端主机以上,您需要使用像在同一服务器上使用多个IP地址这样的技巧。

  • 由于存在与Web中介的安全问题,浏览器到服务器的WebSocket消息具有所有有效载荷数据异或掩码。这会使服务器产生一些CPU利用率来解码消息。但是,在大多数 CPU 架构中,异或是最有效的操作之一,并且通常可提供硬件协助。从服务器到浏览器的消息没有掩码,由于许多WebSockets的用途不需要从浏览器发送大量数据到服务器,因此这不是一个大问题。


3
在HTTP流媒体(Caplin使用的方式)中,HTTP握手不会在每个消息传递中发生 - 我自己已经多次实现过。它本质上只是一个开放的(单向)套接字连接。HTTP流媒体的性能将非常接近WebSockets(但有几个警告,其中之一是缺乏双工)。 - David Titarenco
3
Caplin现在提供WebSocket支持。HTTP流是一个不错的选择(正如我们之前所说),但是对于不支持multipart/x-mixed-replace内容类型的浏览器(除Firefox之外的所有浏览器),这意味着XHR.responseText会不断增加,最终必须中断并重新启动流连接,否则浏览器最终会耗尽内存。 - leggetter
@DavidTitarenco,我很想知道您对于Comet/长轮询和WebSocket在该基准测试中延迟差异几乎相差两个数量级的原因有何看法。 - kanaka
2
@leggetter,你有Caplin的HTTP流延迟(往返)与Caplin WebSockets的数据吗?好奇的人想知道。 - kanaka
1
很遗憾,不行。但我会去问一下。 - leggetter
实现Comet的方法有很多种(这是一个有点像伞头的术语)。我的观点是,如果你通过HTTP流(使用分块编码)来实现Comet,你将获得与websocket实现相当甚至相同的延迟。但是,使用长轮询(也称为HTTP推送),每次接收到消息后连接都需要重新初始化,这个优势就不存在了。 - David Titarenco

6

很难对此进行比较,因为我们不知道(平均)有效载荷大小有多大。就底层实现而言,HTTP流和WebSockets几乎是相同的-除了初始握手外,当然使用HTTP时会更复杂。

如果您自己使用C编写WebSocket服务器(如Caplin),您可能不需要太多困难就可以达到这些数字。大多数WebSocket实现都是通过现有的服务器包(如Jetty)完成的,因此比较并不公平。

一些基准测试:
http://webtide.intalio.com/2011/09/cometd-2-4-0-websocket-benchmarks/
http://webtide.intalio.com/2011/08/prelim-cometd-websocket-benchmarks/

但是,如果您查看C事件库基准测试,例如libev和libevent,则数字看起来显着更佳:
http://libev.schmorp.de/bench.html


3
非常感谢您的链接!实际上,HTTP 和 WebSockets 是非常不同的。WebSocket 握手设计成与 HTTP 兼容,以便两种服务可以共享同一个端口。它们通常在同一台服务器上实现,但之后它们就非常不同了。一旦 WebSocket 连接建立,它就是一个全双工和双向的原始通道(更类似于普通套接字)。而且在某些方面,WebSocket 握手实际上比纯粹的 HTTP 更复杂,因为它允许 CORS 验证,并且握手过程中需要 SHA1 挑战响应。 - kanaka
2
在服务器向客户端传递消息方面,延迟在初始连接后将非常相似,如果不是完全相同的话。正如@kanaka所指出的那样,WebSockets的好处在于,在建立连接之后,通道是全双工和双向的。因此,如果您要使用HTTP流传输进行双向消息传递的基准测试,其中需要第二个短暂的HTTP用于客户端到服务器的通信,则WebSocket选项可能会大大优于它。Caplin现在提供WebSocket支持,因此我有信心他们可以打败100k个连接。 - leggetter
1
@leggetter,我的理解是,在HTTP/1.0上进行长轮询时,你需要在两个方向上设置套接字和HTTP请求/响应头。使用keep-alive的HTTP/1.1长轮询允许套接字被重复使用,但我认为HTTP请求/响应头仍然会被发送/接收。找到一个确定性答案比我预期的更困难。我非常想看到比较各种Comet/AJAX/长轮询解决方案的线路转储,以便我可以看到确切发生了什么。 - kanaka
1
@kanaka 我对于HTTP/1.0和HTTP/1.1上的HTTP长轮询的理解与你相同。然而,HTTP流是不同的,因为连接在消息之间保持打开状态。如果使用多部分替换,则会发送附加数据以界定消息部分。但是标准的流仅通过线路发送新数据,没有附加头,所以一旦建立连接,我认为它与WebSocket连接一样有效。问题在于responseText缓冲区增长,连接最终需要断开并重新连接。 - leggetter
根据Wikipedia关于HTTP Pipelining的文章所述, 只有Opera浏览器支持keep-alive。这个信息是通过谷歌SPDY协议文章发现的。 - leggetter
你不必使用流水线传输,你可以使用分块编码,参考:http://en.wikipedia.org/wiki/Chunked_transfer_encoding - 这是我以前的做法,每个消息只需要发送 [字节数]\r\n[消息]\r\n。你可以用多种方式来评估流。最简单的方法是检查 XHR 状态标志,并在获取新信息时解释它。然而,在 IE 中这种方法不起作用(存在几种混乱的 iframe 解决方法)。此外,我从未遇到任何浏览器因 responseText 太大而关闭连接。限制可能设置为几 MB。 - David Titarenco

4
忽略任何形式的轮询,因为如其他地方所解释的,当更新速率很高时,会引入延迟,JavaScript流媒体的三种最常见技术是:
  1. WebSocket
  2. Comet XHR/XDR 流
  3. Comet Forever IFrame
WebSocket 是目前最干净的解决方案,但浏览器和网络基础设施仍存在不支持它的问题。越早能依赖它越好。
XHR/XDR 和 Forever IFrame 都可以将数据从服务器推送到客户端,但需要各种技巧才能在所有浏览器上始终正常工作。以我的经验来看,这些 Comet 方法总是比 WebSockets 稍微慢一些,其中一个原因是需要更多的客户端 JavaScript 代码才能使其工作 - 但从服务器的角度来看,通过电线发送数据的速度是相同的。
这里有一些WebSocket基准图表,这次是针对我们的产品my-Channels Nirvana
跳过多播和二进制数据图表,直接滚动到页面底部的最后一个图表(JavaScript 高更新速率)。
总结一下,结果显示Nirvana WebSocket将50个事件/秒传递给2,500k用户,延迟为800微秒。在5,000个用户(共流式传输250k个事件/秒)时,延迟为2毫秒。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接