服务器发送事件与轮询

Posted

技术标签:

【中文标题】服务器发送事件与轮询【英文标题】:Server-Sent Events vs Polling 【发布时间】:2012-03-12 22:36:41 【问题描述】:

html5 SSEs 和直接 Ajax 轮询之间是否存在很大差异(在性能、浏览器实现可用性、服务器负载等方面)?从服务器端看,EventSource 似乎每隔 3 秒左右就会访问指定的页面(尽管我知道时间是灵活的)。

当然,在客户端设置比设置计时器并每隔一段时间使用$.get 更简单,但是还有什么其他的吗?它会发送更少的标头,还是做一些我缺少的魔法?

【问题讨论】:

【参考方案1】:

Ajax 轮询会增加大量 HTTP 开销,因为它会不断地建立和断开 HTTP 连接。正如HTML5 Rocks 所说,“另一方面,服务器发送的事件从一开始就被设计为高效。”

服务器发送的事件会打开一个长期存在的 HTTP 连接。然后服务器在收到数据时单向发送数据,客户端无需请求或执行任何操作,只需等待消息。

服务器发送事件的一个缺点是,由于它们会创建与服务器的持久连接,因此您可能会与服务器建立许多打开的连接。一些服务器handle massive numbers of concurrent connections better 比其他服务器。也就是说,您在轮询以及不断重新建立这些连接的开销方面会遇到类似的问题。

服务器发送的事件非常好supported in most browsers,当然值得注意的例外是 IE。但是有一个couple 和一个polyfills(和一个jQuery plugin)可以解决这个问题。

如果你做的事情只需要单向通信,我肯定会选择服务器发送的事件。正如您所提到的,服务器发送的事件在客户端实现起来往往更简单、更清晰。您只需要为消息和事件设置侦听器,浏览器会处理低级别的事情,例如在断开连接时重新连接等。在服务器端,它也很容易实现,因为它只使用简单的文本。如果您发送 JSON 编码的对象,您可以通过 JSON.parse() 在客户端轻松地将它们转换为 javascript 对象。

如果您在服务器上使用 php,您可以使用 json_encode() 将字符串、数字、数组和对象转换为正确编码的 JSON。其他后端语言也可能提供类似的功能。

【讨论】:

但是服务器端的资源呢?每 5 秒 1 次 ajax 请求不是比为每个用户永久保持连接更好吗? 使用 SSE 有一些注意事项,其中更重要的 2 点是它们只接受 GET 请求并且不允许您指定标头。【参考方案2】:

我只会对刚才所说的内容添加一个更高的视角,那就是 SSE 是发布-订阅模型,而不是 AJAX 的持续轮询。

通常,两种方式(轮询和发布-订阅)都试图解决如何在客户端上保持最新状态的问题。

1) 轮询模型

这很简单。客户端(浏览器)首先获得一个初始状态(页面),为了更新它,它需要定期请求状态(页面或其部分)并将结果处理为当前状态(刷新整个页面或将其智能渲染到它的AJAX 的一部分)。

当然,一个缺点是如果服务器状态没有发生任何事情,则资源(CPU、网络等)会被不必要地使用。另一个是即使状态发生变化,客户端也只能在下一个轮询期间获得它,而不是尽快。人们经常需要评估两件事之间的良好时期折衷。

另一个轮询示例是线程中的 spinwait。

2) 发布-订阅模型

它的工作原理如下:

(客户端首先请求并显示一些初始状态) 客户端订阅服务器(发送一个请求,可能带有一些上下文,如事件源) 服务器将对客户端的引用标记到其客户端引用存储库中 在状态更新的情况下,服务器根据对它持有的客户端的引用向客户端发送通知;即它不是对请求的响应,而是由服务器发起的消息 好客户在对通知不再感兴趣时退订

这是 SSE,或在线程内等待的事件,作为另一个示例。 如前所述,一个自然的缺点是服务器必须了解其所有订阅的客户端,这取决于实现,可能是一个问题。

【讨论】:

以上是关于服务器发送事件与轮询的主要内容,如果未能解决你的问题,请参考以下文章

EventSource 与轮询 ajax 的效率/开销?

Web 套接字、长轮询、服务器发送事件和永久帧之间有啥区别?

服务器客户端通信:长轮询、彗星和服务器发送事件 (SSE)

社交 Android 应用程序的通知系统 - 推送与轮询以及如何使服务器“推送”

HTML5 服务器发送事件原型 - 模棱两可的错误和重复轮询?

LVS负载均衡之IPVSADM命令说明与轮询解释