如何在Spring中创建非阻塞@RestController Web服务?

mem*_*und 6 java spring spring-mvc spring-boot spring-web

我有一个@RestControllerWeb 服务方法,可能会通过长时间运行的服务调用来阻止响应线程。如下:

@RestController
public class MyRestController {
    //could be another webservice api call, a long running database query, whatever
    @Autowired
    private SomeSlowService service;

    @GetMapping()
    public Response get() {
        return service.slow();
    }

    @PostMapping()
    public Response get() {
        return service.slow();
    }
}
Run Code Online (Sandbox Code Playgroud)

问题:如果 X 用户在这里调用我的服务怎么办?正在执行的线程将全部阻塞,直到返回响应。因此消耗了“最大连接数”、最大线程数等。

我记得前段时间读过一篇关于如何解决此问题的文章,通过以某种方式停放线程直到收到缓慢的服务响应。这样这些线程就不会阻塞,例如tomcat最大连接/池。

但我再也找不到它了。也许有人知道如何解决这个问题?

g00*_*00b 4

有一些解决方案,例如使用异步请求CompletableFuture在这些情况下,一旦返回(不一定完成),DeferredResult线程将再次空闲。Callable


例如,假设我们这样配置 Tomcat:

server.tomcat.max-threads=5 # Default = 200
Run Code Online (Sandbox Code Playgroud)

我们有以下控制器:

@GetMapping("/bar")
public CompletableFuture<String> getSlowBar() {
    return CompletableFuture.supplyAsync(() -> {
        silentSleep(10000L);
        return "Bar";
    });
}

@GetMapping("/baz")
public String getSlowBaz() {
    logger.info("Baz");
    silentSleep(10000L);
    return "Baz";
}
Run Code Online (Sandbox Code Playgroud)

如果我们一次触发 100 个请求,则您必须等待至少 200 秒才能getSlowBar()处理所有调用,因为给定时间只能处理 5 个请求。另一方面,对于异步请求,您必须等待至少 10 秒,因为所有请求可能会立即处理,然后该线程可供其他人使用。

CompletableFuture之间有区别吗?结果没有任何差异,它们的行为都相似。CallableDeferredResult

不过,处理线程的方式有点不同:

  • 使用Callable,您依赖 Spring 执行Callable使用TaskExecutor
  • 你必须DeferredResult自己处理线程。例如,通过执行ForkJoinPool.commonPool().
  • 使用CompletableFuture,您可以依赖默认线程池 ( ForkJoinPool.commonPool()),也可以指定您自己的线程池。

除此之外,CompletableFutureCallable是Java规范的一部分,而DeferredResult是Spring框架的一部分。


但请注意,即使线程被释放,连接仍然对客户端保持打开状态。这意味着使用这两种方法,一次可以处理的最大请求数限制为 10000,并且可以配置为:

server.tomcat.max-connections=100 # Default = 10000
Run Code Online (Sandbox Code Playgroud)

  • @membersound正如我在回答中提到的,它们的不同之处在于您对正在使用的线程池有多少控制权。此外,由于“Callable”和“CompletableFuture”是 Java 规范的一部分,因此它们具有更丰富的生态系统。例如,您可以找到像 [completable-futures](https://github.com/spotify/completable-futures) 这样的库,它们允许您使用“CompletableFuture”做更多事情。如果这些事情对你来说很重要,那么这不仅仅是品味问题。 (2认同)