如何避免轮询耗时的异步REST请求?

时间:2018-03-16 11:08:40

标签: rest asynchronous polling

问题在于如何设计REST Web服务,该服务执行耗时的工作(数秒和数分钟的数量级)。

最快的解决方案是按以下步骤进行:

  1. 客户端向服务器发送POST请求(POST / job),答案有 HTTP状态202并将包含作业ID;
  2. 客户端使用GET定期询问作业状态(例如GET /job/:id/status);
  3. 当作业完成时,客户端使用GET请求结果(例如GET /job/:id/result)。
  4. 我不喜欢的是第2步,因为正在进行许多作业,服务器不必要地过载。 为了避免这种情况,我想到了另外两个解决方案:

    • 当客户端执行第一个POST请求时,它还会提供一个可以的URL 用作服务器的回调。当服务器结束时 详细说明,它将通过GET / POST通过此URL通知客户端 请求;
    • 服务器提供客户端可以注册的WebSocket 并在工作完成时获得“通知”;

    所有这三种解决方案都有我不喜欢的方面:

    1. 轮询: 服务器重载;
    2. 回调: 客户端必须为服务器提供URL;
    3. websocket: 为什么要向REST网络服务引入另一个“技术”? 也许,在那时,最好只使用websockets来做 所有请求。
    4. 还有其他解决方案吗?如果不是,您认为哪三个更可靠?

2 个答案:

答案 0 :(得分:1)

轮询往往非常容易实现,而且非常可靠。可靠性来自解决方案的简单性。轮询请求一般应该是非常便宜的请求。通过退回轮询频率并一次检查多个作业(例如,在一个请求中发送1000个ID),可以提高轮询效率。

任何非民意调查解决方案都必须是有效通知的一种形式。您建议的HTTP回调解决方案要求客户端运行Web服务器。它可以完成,但似乎没必要。

Web套接字的想法也很明显。您将需要重新连接逻辑并处理在客户端碰巧断开连接时作业完成的情况。客户端代码可能涉及线程,因为您可能不希望每个作业有一个Web套接字连接。

比使用网络套接字更简单的想法是使用"彗星" HTTP请求。服务器保持HTTP请求打开,直到作业完成。这对于异步IO非常有效,因此在等待时不会阻塞任何线程。但是如果断开连接,必须实施一些重新连接策略。

您可以让服务器将消息写入客户端读取的队列。

所有这些通知解决方案往往比简单的轮询解决方案复杂得多。他们需要更多的开发人员时间,并且会更频繁地中断生产。但它们可以降低延迟并减少资源使用。我试图让民意调查工作。可能它会起作用,你很快就完成了。

答案 1 :(得分:0)

你几乎自己回答了你的问题。问题是,根据您的要求,您会选择哪种方法。你的所有建议都是你问题的解决方案,但你必须加以重视并自行决定。但是我认为你对方法1过分夸大了。如果你制定了一个进展策略,比如不定期地进行民意调查(不是游泳池),可以说30秒后的第一轮民意调查,20分钟后的下一轮民意调查,10天后的民意调查,那么也许重复那个序列,那么服务器就不会那么紧张了。

此外,如果您可以某种方式预测作业的复杂性,您选择的时间间隔可能基于POST请求的响应。因此,如果工作需要几分钟,例如每5秒轮询就没有意义。您可以制定一个类似阵列的策略(时间以秒为单位):[300,120,60,30,20,10],这意味着您将先等待5分钟,然后再等待2分钟,然后等待1分钟等等 - 您将获得它,你可以间隔10秒完成。由于工作本身可能需要几分钟,我认为如果结果延迟了几秒钟就好了,即准备就绪,但没有按时服务。