HTML WebSockets为每个客户端维护一个开放连接吗?这样做是否可扩展?

171

我很想知道有关HTML WebSockets可扩展性的任何信息。根据我所读的内容,每个客户端都将与服务器保持开放的通信线路。我只是想知道这如何扩展以及服务器可以处理多少个开放的WebSocket连接。也许在现实中保持这些连接不是问题,但它感觉像是一个问题。


2
没有所谓的HTML WebSocket。你指的是HTTP WebSocket。 - user207421
5个回答

217

在大多数方面,WebSockets 可能比 AJAX/HTML 请求更具有伸缩性。然而,这并不意味着 WebSockets 可以代替所有使用 AJAX/HTML 的情况。

每个 TCP 连接本身在服务器资源方面消耗很少。经常设置连接可能很昂贵,但维护空闲连接几乎是免费的。通常遇到的第一个限制是可以同时打开的最大文件描述符数(套接字消耗文件描述符)。这通常默认为1024,但很容易配置得更高。

试过将 Web 服务器配置为支持数万个同时的 AJAX 客户端吗?把这些客户端变成 WebSockets 客户端,这可能是可行的。

HTTP 连接虽然不会长时间创建打开文件或消耗端口号,但在几乎每个其他方面都更加昂贵:

  • 每个 HTTP 连接携带了很多很少使用的内容:cookies、content type、content length、user-agent、服务 id、日期、last-modified 等等。一旦建立了 WebSockets 连接,只有应用程序需要发送和接收的数据才会来回传输。

  • 通常,HTTP 服务器被配置为记录每个 HTTP 请求的开始和完成,占用磁盘和 CPU 时间。将记录 WebSockets 数据的开始和完成变为标准,但是在 WebSockets 连接进行双向传输时,不会有任何额外的日志记录开销(除非应用程序/服务设计成这样)。

  • 通常,使用 AJAX 的交互式应用程序要么持续轮询,要么使用某种长轮询机制。WebSockets 是一种更加清洁(和低资源)的方式,可以使用更多事件模型,在现有连接上服务器和客户端互相通知彼此,当他们有报告内容时。

  • 绝大多数生产环境中常用的Web服务器都有一个进程(或线程)池来处理HTTP请求。随着压力的增加,池的大小将会增加,因为每个进程/线程一次只能处理一个HTTP请求。每个额外的进程/线程使用更多的内存,而创建新的进程/线程比创建新的套接字连接要昂贵得多(这些进程/线程仍然必须执行该操作)。现在,大多数流行的WebSocket服务器框架都采用事件驱动的路线,这倾向于扩展和性能更好。

  • WebSocket的主要优点是互动式Web应用程序具有更低的延迟连接。它将比HTTP AJAX/long-poll更好地扩展和消耗更少的服务器资源(假定应用程序/服务器被正确设计),但我认为WebSocket的主要优点是较低的延迟,因为它将使新的Web应用程序类别成为可能,而这是现有的AJAX/long-poll的高开销和延迟所不可能实现的。

    一旦WebSocket标准变得更加完善并获得更广泛的支持,对于需要频繁与服务器通信的大多数新交互式Web应用程序来说,使用它将是合理的。对于现有的交互式Web应用程序,这将取决于当前AJAX/long-poll模型的运行情况。转换的工作量是不小的,因此在许多情况下,成本就不值得收益。

    更新:

    有用链接: 使用Node.js在AWS上拥有600,000个并发WebSocket连接


    4
    非常棒的回答。感谢您抽出时间回复。 - rmontgomery429
    7
    尽管如此,我仍然不知道当你遇到瓶颈时如何进行扩展。WebSockets确实消耗更少的资源(它们可以纵向扩展),但HTTP在横向扩展方面表现出色。理论上,我可以添加服务器以实现无限扩展。我一直困惑于如何扩展一旦使用完单个服务器的容量。您有什么想法吗? - Sean Clark Hess
    6
    @WebSockets在水平扩展方面并不一定比较劣。它只是为那些不容易水平扩展的新应用程序提供了可能性。例如,对于提供静态数据,一群WebSocket服务器的水平扩展能力与(甚至更好)一群HTTP服务器相当。一个低延迟的实时游戏无论使用何种传输方式都很难进行水平扩展(而使用HTTP则几乎不可行)。真正的问题是你的数据/应用程序能否进行扩展。如果可以扩展,那么你选择使用HTTP还是WebSocket应该基于其他因素:延迟、部署选项、浏览器支持等等。 - kanaka
    3
    一个更正 - TCP连接由目的地IP地址和目的地端口组成。这意味着±64k端口限制实际上仅适用于单个客户端。从理论上讲,服务器可以拥有任意数量的打开连接,仅受其硬件限制。 - Rizon
    @Rizon,说得对。我已更新答案,并更改了开放端口限制,而是提到了文件描述符限制,这是人们经常首先遇到的问题。 - kanaka
    显示剩余9条评论

    38

    需要澄清的是:在这种情况下,服务器可以支持的客户端连接数与端口无关,因为服务器通常只在一个单一端口上侦听WS/WSS连接。其他评论者想要引用的应该是文件描述符。您可以将最大文件描述符数量设置得很高,但是您必须注意每个打开的TCP/IP套接字的套接字缓冲区大小累加的情况。以下是一些附加信息:https://serverfault.com/questions/48717/practical-maximum-open-file-descriptors-ulimit-n-for-a-high-volume-system

    至于通过WS相对于HTTP减少延迟,这是真的,因为除了初始WS握手之外,不再解析HTTP头文件。此外,随着越来越多的数据包被成功发送,TCP拥塞窗口扩大,有效地缩短了往返时间。


    1
    据我所知,有一个入站端口,但每个连接都会打开一个出站端口。这实际上只是C10k问题的一部分。 - Arnaud Bouchez

    17
    任何现代单服务器都能够同时服务数千个客户端。它的HTTP服务器软件只需要是事件驱动(IOCP)导向的(我们不再使用旧的Apache一个连接=一个线程/进程方程式)。即使是Windows内置的HTTP服务器(http.sys)也是IOCP导向的,非常高效(在内核模式下运行)。从这个角度来看,在WebSockets和常规HTTP连接之间进行扩展不会有太大的差别。一个TCP/IP连接使用的资源很少(比一个线程少得多),而现代操作系统被优化用于处理很多并发连接:WebSockets和HTTP只是OSI 7应用层协议,继承自TCP/IP规范。
    但是,从实验中,我看到WebSockets存在两个主要问题:
    1. 它们不支持CDN;
    2. 它们存在潜在的安全问题。

    因此,我建议对于任何项目采取以下措施:

    • 仅使用WebSockets进行客户端通知(带有回退机制以进行长轮询-周围有很多库);
    • 使用RESTful / JSON处理所有其他数据,使用CDN或代理进行缓存。
    在实践中,完整的WebSockets应用程序无法很好地扩展。只需将WebSockets用于它们的设计目的:从服务器向客户端推送通知。
    关于使用WebSockets可能存在的问题:
    1. 考虑使用CDN
    今天(几乎四年后),Web扩展涉及使用内容传递网络(CDN)前端,不仅用于静态内容(html、css、js),还包括你的(JSON)应用程序数据
    当然,您不会将所有数据放在CDN缓存中,但在实践中,许多常见内容不会经常更改。我怀疑您的REST资源中有80%可以被缓存...即使是一分钟(或30秒)的CDN过期超时也足以为您的中央服务器提供新的活力,并大大增强应用程序的响应能力,因为CDN可以进行地理调整...
    据我所知,CDN尚未支持WebSockets,并且我怀疑它永远不会支持。WebSockets是有状态的,而HTTP是无状态的,因此更容易被缓存。事实上,为了使WebSockets适合CDN,您可能需要切换到无状态的RESTful方法...这将不再是WebSockets。
    2. 安全问题
    WebSockets存在潜在的安全问题,特别是关于DOS攻击。有关新安全漏洞的说明,请参见这组幻灯片这个webkit票证
    WebSockets避免了在OSI 7应用层级别进行任何数据包检查的机会,这在任何商业安全中都变得非常普遍。事实上,WebSockets使传输模糊,因此可能是主要的安全漏洞。

    2
    @ArnaudBouchez - 对于CDN的精彩阐述点赞。快速跟进问题 - 您认为事件传递网络的可行性如何?这些网络是基于CDN模式,但旨在通过WebSockets或其他尚未出现的技术传递流数据等。 - quixver
    我认为你说得非常正确。CDN点非常有道理。如今,使用CDN或缓存轻松扩展已经非常普遍。WEBsockets使这种类型的扩展变得困难。因此,这是一个非常重要的考虑点。 - jolumg

    8
    以这种方式考虑:保持一个开放的连接比为每个请求打开一个新的连接更便宜(需要考虑协商开销,记住这是TCP)。
    当然,这取决于应用程序,但对于长期实时连接(例如AJAX聊天),保持连接开放要好得多。
    最大连接数将受到套接字可用空闲端口数量的限制。

    你可以通过使用HTTP/1.1的keep alive选项而不使用WebSocket来保持连接开放。我不确定我理解你的意思。 - Arnaud Bouchez
    1
    +1. 人们往往会忘记建立TCP连接需要syn/ack/ack,而TLS需要更多的往返以进行密钥交换。 - quixver
    1
    @ArnaudBouchez 请查看http://en.wikipedia.org/wiki/HTTP_persistent_connection#HTTP_1.1。WebSockets可以一直保持开放状态,而且不像长轮询和其他替代方案那样具有hackish的特点。 - kaoD

    -4

    不,它不能扩展,会给中间路由交换机带来巨大的工作量。然后在服务器端,页面故障(您必须保留所有这些描述符)达到了很高的值,并且将资源带入工作区域的时间增加了。这些服务器大多是用JAVA编写的,保持那些亿万个套接字可能比销毁/创建一个更快。 当您在计算机上运行此类服务器时,任何其他进程都无法移动。


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