当期望服务器端的一次性响应时,使用长轮询与Websocket

问题描述:

我已经阅读了许多有关实时推送通知的文章.简历是,只要您不关心浏览器的100%兼容性,通常都首选websocket技术.然而,一篇文章指出

I have read many articles on real-time push notifications. And the resume is that websocket is generally the preferred technique as long as you are not concerned about 100% browser compatibility. And yet, one article states that

长时间轮询-可能与您交换单个呼叫时 服务器,并且服务器正在后台做一些工作.

Long polling - potentially when you are exchanging single call with server, and server is doing some work in background.

这正是我的情况.用户按下一个按钮,该按钮将在服务器端启动一些复杂的计算,并且一旦答案准备好,服务器就会向客户端发送一个推送通知.问题是,对于一次响应,我们可以说长轮询比websockets更好的选择吗? 或者,除非我们担心过时的浏览器支持,并且如果我要从头开始项目,那么在推送协议方面,总是应该优先选择websockets而不是长轮询吗?

This is exactly my case. The user presses a button which initiates some complex calculations on server-side, and as soon as the answer is ready, the server sends a push-notification to the client. The question is, can we say that for the case of one-time responses, long-polling is better choice than websockets? Or unless we are concerned about obsolete browsers support and if I am going to start the project from scratch, websockets should ALWAYS be preferred to long-polling when it comes to push-protocol ?

问题是,我们可以说,对于一次性答复, 长轮询比websockets是更好的选择?

The question is, can we say that for the case of one-time responses, long-polling is better choice than websockets?

并非如此.长时间轮询效率低下(多次传入请求,服务器必须多次检查长时间运行的作业的状态),尤其是在通常的时间周期足够长而您将不得不多次轮询的情况下.

Not really. Long polling is inefficient (multiple incoming requests, multiple times your server has to check on the state of the long running job), particularly if the usual time period is long enough that you're going to have to poll many times.

如果给定的客户端页面仅可能执行一次此操作,那么您实际上可以采用任何一种方式.每种机制都有其优点和缺点.

If a given client page is only likely to do this operation once, then you can really go either way. There are some advantages and disadvantages to each mechanism.

在5到10分钟的响应时间中,即使您确保服务器端保持打开状态的时间如此长,您也不能认为单个http请求会一直保持等待状态.客户端或中间网络设备(代理等)只是不使初始http连接保持打开状态的时间如此长.如果可以的话,那将是最有效的机制.但是,我认为您不能依靠不受控制的随机网络配置和客户端配置.

At a response time of 5-10 minutes you cannot assume that a single http request will stay alive that long awaiting a response, even if you make sure the server side will stay open that long. Clients or intermediate network equipment (proxies, etc...) just make not keep the initial http connection open that long. That would have been the most efficient mechanism if you could have done that. But, I don't think you can count on that for a random network configuration and client configuration that you do not control.

因此,这为您提供了一些我认为您已经知道的选项,但是在这里我将为其他人介绍完整性.

So, that leaves you with several options which I think you already know, but I will describe here for completeness for others.

选项1:

  • 与服务器建立Websocket连接,您可以通过它接收推送响应.
  • 发出http请求以启动长时间运行的操作.返回该操作已成功启动的响应.
  • 稍后再接收websocket推送响应.
  • 关闭webSocket(假设此页面将不再执行此操作).

选项2:

  • 发出http请求以启动长时间运行的操作.返回该操作已成功启动的响应,并可能提供某种taskID,可将其用于将来的查询.
  • 使用http长时间轮询"来等待"答案.由于这些请求可能会在收到响应之前超时",因此您必须定期进行长时间轮询,直到收到响应为止.

选项3:

  • 建立webSocket连接.
  • 通过webSocket连接发送消息以启动操作.
  • 稍后再接收到该操作已完成的响应.
  • 关闭webSocket连接(假设此页面将不再使用它).

选项4:

  • 与选项3相同,但是使用socket.io而不是普通的webSocket为您提供心跳信号和自动重新连接逻辑,以确保webSocket连接保持活动状态.

如果仅从网络和服务器效率的角度来看问题,那么选项3或4可能是最有效的.您只需在客户端和服务器之间建立一个TCP连接的开销,并且一个连接用于所有流量,并且该连接上的流量非常有效,并且支持实际推送,因此可以尽快通知客户端.

If you're looking at things purely from the networking and server efficiency point of view, then options 3 or 4 are likely to be the most efficient. You only have the overhead of one TCP connection between client and server and that one connection is used for all traffic and the traffic on that one connection is pretty efficient and supports actual push so the client gets notified as soon as possible.

从体系结构的角度来看,我不是选项1的粉丝,因为当您使用一种技术发起请求然后通过另一种技术发送响应时,它似乎有点令人费解,这需要您在以下两者之间建立相关性:发起传入的HTTP请求和已连接的webSocket的客户端.可以做到,但这是服务器上额外的簿记.选项2在结构上很简单,但是效率低下(定期轮询服务器),因此也不是我的最爱.

From an architecture point of view, I'm not a fan of option 1 because it just seems a bit convoluted when you initiate the request using one technology and then send the response via another and it requires you to create a correlation between the client that initiated an incoming http request and a connected webSocket. That can be done, but it's extra bookkeeping on the server. Option 2 is simple architecturally, but inefficient (regularly polling the server) so it's not my favorite either.