【问题标题】:Long Polling in Spring春季长轮询
【发布时间】:2017-01-26 16:00:56
【问题描述】:

我们有一个比较特殊的情况,我们需要与外部 API 交互,这需要我们长时间轮询他们的端点以获取他们所谓的实时事件。

问题是我们可能有多达 80,000 人/设备在任何给定时间访问此端点,监听事件,每个设备/人 1 个连接。

当客户端从我们的 Spring 服务发出长轮询事件的请求时,我们的服务会依次对外部 API 进行异步调用以长轮询事件。外部 API 已定义 minimum 长轮询超时可设置为 180 秒。

所以在这里我们遇到了一个带有队列的线程池将无法工作的情况,因为如果我们有一个线程池具有类似(5 min,10 max,10 queue)的东西,那么正在工作的 10 个线程可能会占用在当前 10 个中的一个完成之前,聚光灯和队列中的 10 个将没有机会。

我们需要服务或失败(我们将在其后面放置负载平衡器等),但我们不希望在没有实际轮询发生的情况下让客户端挂起。

我们一直在研究为此使用 DeferredResult,并从控制器返回。

有什么好调的

@RequestMapping(value = "test/deferredResult", method = RequestMethod.GET)
    DeferredResult<ResponseEntity> testDeferredResult() {
        final DeferredResult<ResponseEntity> deferredResult = new DeferredResult<ResponseEntity>();
        CompletableFuture.supplyAsync(() -> testService.test()).whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));
        return deferredResult;
    }

我在质疑我是否走在正确的道路上,我是否应该为CompletableFuture.supplyAsync() 方法提供一个执行器以及什么样的执行器(和配置)才能最好地完成我们的任务。

我已经阅读了各种文章、帖子等,我想看看是否有人有任何知识可能有助于我们的具体情况。

【问题讨论】:

  • 也许你可以给一个机会来vert'x?它有非常好的异步支持

标签: java spring


【解决方案1】:

如果您使用阻塞 IO,您所描述的问题听起来并不像可以很好地解决的问题。因此,您走在正确的道路上,因为 DeferredResult 允许您使用任何线程生成结果,而不会阻塞 servlet-container 线程。

关于上游调用长池化 API,您还需要一个 NIO 解决方案。如果您使用 Netty 客户端,则可以使用单个线程管理数千个套接字。当 Netty 中的 NIO 选择器检测到数据时,你会得到一个通道回调,并最终委托给 Netty 工作线程池中的一个线程,你可以调用deferredResult.setResult。如果您不进行阻塞 IO,则工作池的大小通常根据 CPU 核心数确定,否则您可能需要更多线程。

仍有许多挑战。

  • 您可能需要不止一台服务器(或网络接口),因为只有 65K 端口。
  • Java 中的套接字没有写入超时,因此如果客户端拒绝从套接字读取数据,并且您发送的数据多于套接字缓冲区,您将阻塞 Netty 工作线程,然后一切都会停止( 反向缓慢的懒猴攻击)。这是大型异步设置中的一个经典问题,也是使用 Hystrix(Netflix 出品)等框架的原因之一。

【讨论】:

  • 太棒了,谢谢。这就是我一直在寻找的确认和足够的信息,以便继续(希望)有效的方向。
猜你喜欢
  • 2015-10-19
  • 2013-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 2011-04-20
  • 2017-10-06
  • 2019-05-28
相关资源
最近更新 更多