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

Mar*_*tin 7 rest http

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

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

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

Voi*_*son 1

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

简短的回答 - 为什么不只使用 Event Store 作为参考实现,并调整他们的解决方案以匹配您的实现限制?

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

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

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

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

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

就其本身而言,这些部分让您在符合 REST 架构约束的事件处理器方面取得了很大的领先优势。您需要在其上添加长轮询即可。

要大致了解如何自行实现长轮询,您可以查看由 Michael Barker(LMAX Disruptor维护者)编写的票务演示

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

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

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

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

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

遥远的将来客户端正在寻找的位置在缓存中不可用,并且我们预计我们无法在指定的时间内满足请求。所以我们现在就回复,让客户决定该怎么做。

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

还需要考虑一些边缘情况 - 如果传入的批次非常大,那么您可能需要逐出客户端正在等待的事件,然后才有机会发送它们。