您能否分享任何最新的手册或在这里解释如何使用最新的 Spring (Spring Boot) 实现 REST 长轮询端点?
我此时发现的所有内容都已经过时,并且是几年前发布的。
所以,我提出了一个问题,长轮询仍然是一个好方法吗?我知道 chess.com 中使用了它
对于长轮询请求,您可以使用
DeferredResult
。当您返回 DeferredResult
响应时,请求线程将空闲,并且该请求将由工作线程处理。这是一个例子:
@GetMapping("/test")
DeferredResult<String> test(){
long timeOutInMilliSec = 100000L;
String timeOutResp = "Time Out.";
DeferredResult<String> deferredResult = new DeferredResult<>(timeOutInMilliSec, timeOutResp);
CompletableFuture.runAsync(()->{
try {
//Long polling task; if task is not completed within 100s, timeout response returned for this request
TimeUnit.SECONDS.sleep(10);
//set result after completing task to return response to client
deferredResult.setResult("Task Finished");
}catch (Exception ex){
}
});
return deferredResult;
}
此请求演示等待 10 秒后提供响应。如果您设置
sleep(100)
或更长时间,您将收到超时响应。
查看this以获取更多选项。
请注意,使用 Spring MVC 堆栈时,如果不利用 NIO 组件(例如 Reactive Stack 中的组件),就不可能创建有效的长轮询实现。
阻塞实现效率如此低下的原因是,即使您生成了一个新线程,它们也会阻塞正在运行的线程。当您像 @GolamMazid Sajib 的答案一样生成一个新线程时,您只需更改被阻止的线程即可。虽然现在工作线程是空闲的,但是后台线程正在被阻塞。
假设您已经创建了 @GolamMazid Sajib 提供的长轮询解决方案:
@GetMapping("/test")
DeferredResult<String> test(){
long timeOutInMilliSec = 100000L;
String timeOutResp = "Time Out.";
DeferredResult<String> deferredResult = new DeferredResult<>(timeOutInMilliSec, timeOutResp);
CompletableFuture.runAsync(()->{
try {
//Long polling task; if task is not completed within 100s, timeout response returned for this request
TimeUnit.SECONDS.sleep(10);
//set result after completing task to return response to client
deferredResult.setResult("Task Finished");
}catch (Exception ex){
}
});
return deferredResult;
}
CompletableFuture.runAsync
方法将执行上下文更改为线程池。
现在,假设您同时收到 1000 个请求。现在,每个工作线程立即处理 1000 个请求。然而,后台线程池现在成为瓶颈。假设池中有 50 个线程。您的吞吐量变为每秒 5 个请求。此外,请求花费的时间远远超过 10 秒,因为它们必须等待后台线程完成。大多数请求都会因为100秒超时而超时。
如果你想实现长轮询,你应该考虑实现 NIO 解决方案。