通过REST API实现对长轮询的服务器端响应

时间:2016-07-10 10:41:23

标签: rest http

假设您正在通过HTTP为服务器“房间”设计REST API,其中订阅客户端希望监视发生在房间中的公共事件(例如,新参与者加入房间,另一个人离开房间,等等。 。)通过提出长轮询请求。

从服务器端角度实现此目的的最佳方法是什么,以便客户端不会错过连续轮询之间的任何事件?例如,服务器是否应该实现需要存在于队列中的事件队列,直到所有订户都获得它们为止?

是否有关于设计此类API的互联网上的任何教程,示例和一些理论以及从服务器角度考虑应考虑的所有事项?

5 个答案:

答案 0 :(得分:1)

答案非常简短 - 为什么不使用EventStore

简短回答 - 为什么不将Event Store用作reference implementation,并调整their solution以符合您的实施限制?

  

从服务器端角度实现此目的的最佳方法是什么,以便客户端不会错过连续轮询之间的任何事件?例如,服务器是否应该实现需要存在于队列中的事件队列,直到所有订户都获得它们为止?

REST本身提供了一些指导原则。应该没有存储在服务器上的应用程序状态;客户端发送的消息应包括服务器完成请求所需的任何客户端状态(如事件流中的当前位置)。请求中标识的资源是抽象 - 因此客户端可以发送消息,例如"事件7"之后发生的事件,即使下一个事件尚不存在也是有意义的。应该遵守统一接口,以允许通过服务器控制之外的高速缓存等进行扩展。资源状态的表示应该是超媒体,其控制允许客户端在消耗了当前可用的消息之后前进。

HTTP引入了一些更具体的细节。由于服务器上没有客户端状态跟踪,因此从队列中读取是一种安全的操作。因此,应该使用其中一种安全的HTTP方法(准确地说是GET)进行读取。由于GET实际上并不支持请求中的内容主体,因此服务器所需的信息都应该打包到请求的标头中。

换句话说,URI用于指定事件流中客户端的当前位置。

Atom Syndication为事件处理提供了良好的超媒体格式 - 事件流映射到提要,事件映射到条目。

这些部分本身可以让您在符合REST体系结构约束的事件处理器上领先一步。 只是需要对其进行长时间轮询。

要大致了解如何自行实施长轮询,可以查看由Michael Barker(ticketing demo的维护者)撰写的LMAX Disruptor

迈克尔演示中的基本情节是单个编写器线程正在跟踪(a)当前正在等待更新的所有客户端和(b)事件的本地缓存。该线程读取一批事件,识别需要通知的请求,依次响应每个请求,然后前进以处理下一批事件。

我倾向于将事件的本地缓存视为环形缓冲区(就像破坏者本身一样,但对于编写者线程是私有的)。写入线程(从HTTP请求中的信息)知道事件流中每个客户端的位置。将该位置与环形缓冲区中的当前指针进行比较,可以将每个待处理请求分类为

远期过去客户端正在寻找的位置已经从缓存中逐出。将客户端重定向到“冷”"流中该位置的持久副本,它可以跟随超媒体控件以赶上当前。

最近的过去客户端正在寻找的位置目前在缓存中可用,因此立即使用可用的事件生成对客户端的响应,并发送该响应。

近期客户端正在寻找的位置在缓存中不可用,但编写者预计能够在SLA到期之前满足该请求。所以我们将客户停放在更多事件到来之前。

远期未来客户端寻求的位置在缓存中不可用,我们预计我们将能够满足请求在规定的时间内。所以我们现在回答,让客户决定做什么。

(如果您获得足够的轮询客户端,您需要开始扩展长轮询服务器,您需要考虑这些服务器不同步的情况,并且客户端从快速服务器定向到已经下降的服务器因此,您希望有适当的工具来跟踪这种情况发生的频率,以便您可以采取适当的补救措施。)

还有一些边缘情况需要考虑 - 如果有一个非常大的批次,那么你可能需要在你有机会发送它们之前驱逐你的客户正在等待的事件。

答案 1 :(得分:1)

简单,让客户端传入他们收到的最后一条消息的时间戳(或id或索引)。

请求GET /rooms/5/messages返回服务器知道的所有消息,例如

[
  {
    "message": "hello",
    "timestamp": "2016-07-18T18:44:34Z"
  },
  {
    "message": "world",
    "timestamp": "2016-07-18T18:47:16Z"
  }
]

然后客户端用GET /rooms/5/messages?since=2016-07-18T18:47:16Z轮询服务器,该服务器返回自那时起的所有消息(如果有的话)或阻止,直到房间有新消息。

答案 2 :(得分:1)

发送包含所有活动的参考号。 Cleint将拨打收到的最新活动的参考号码。如果没有可用事件,您将阻止长轮询请求,并在新参考编号再次提供事件后响应。 如果案例事件已经可用,它将返回在请求引用号事件之后生成的所有事件。

答案 3 :(得分:0)

强烈建议使用WebSockets。查看socket.io。长轮询是一种不一定可取的黑客攻击,并不是真正“支持”。

答案 4 :(得分:0)

长期投票不是一个好主意。特别是当一个人想要监视那些在服务器端发生的变化时。有一些机制,服务器将通知发送给客户端以进行更改。这可以通过使用已经提到的gcoreb来实现Socket.io(Nodejs堆栈)或SignalR(.net堆栈)。