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最大连接/池。
但我再也找不到它了。也许有人知道如何解决这个问题?
有一些解决方案,例如使用异步请求。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使用TaskExecutorDeferredResult自己处理线程。例如,通过执行ForkJoinPool.commonPool().CompletableFuture,您可以依赖默认线程池 ( ForkJoinPool.commonPool()),也可以指定您自己的线程池。除此之外,CompletableFuture和Callable是Java规范的一部分,而DeferredResult是Spring框架的一部分。
但请注意,即使线程被释放,连接仍然对客户端保持打开状态。这意味着使用这两种方法,一次可以处理的最大请求数限制为 10000,并且可以配置为:
server.tomcat.max-connections=100 # Default = 10000
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4897 次 |
| 最近记录: |