![](/img/trans.png)
[英]java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio
[英]Spring Webflux / Reactor: reactor-http-nio vs boundedElastic
我對每個請求落在哪個線程 model 上的一些反應堆概念有點困惑。 我讀了 https://projectreactor.io/docs/core/release/reference但還是不清楚。 讓我們看一個例子:
@Autowired
UserRepository userRepository;
@GetMapping
Flux<User> findAll() {
log.info("findAll request arrived");
final Flux<User> defer = Flux.defer(() -> {
return Flux.fromIterable(userRepository.findAll());
});
return defer;
}
日志:[boundedElastic-4] - 信息 - findAll 請求到達
GET 方法在 Schedulers.boundedElastic 線程池中執行(根據文檔用於 I/O 綁定工作)
@PostMapping
Mono<User> save(@RequestBody User user) {
log.info("save request arrived");
final Mono<User> newUser = Mono.fromCallable(() -> {
final User userMono = userRepository.save(user);
log.info("user saved!");
return userMono;
});
return newUser.subscribeOn(Schedulers.boundedElastic());
}
日志:[reactor-http-nio-6] - 信息 - 保存請求到達
POST 方法落在http-nio線程池上。
@PostMapping("/test")
Mono<User> test() {
log.info("test");
return Mono.just(new User());
}
沒有正文的 POST 也會落在 Schedulers.boundedElastic 上。
@Bean
public ReactiveWebServerFactory reactiveWebServerFactory() {
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
final ReactorResourceFactory reactorResourceFactory = new ReactorResourceFactory();
reactorResourceFactory.setLoopResources(LoopResources.create("http-nio", 4, true));
reactorResourceFactory.setUseGlobalResources(false);
factory.setResourceFactory(reactorResourceFactory);
factory.setPort(8080);
return factory;
}
這就是我配置http-nio線程池的方式。
所以,我的問題是:
http-nio
線程返回到池中。 WebClient
也是如此。 如果您使用的是包裝在 Reactor API 中的阻塞代碼,那么您必須確保它將在不同的線程池上運行。User
而不是Mono<User
。 然后使用不同的線程池是有意義的,這樣你就不會阻塞http-nio
線程。 但是,為了確保執行線程將被切換,您必須使用 flatMap 以便代碼如下所示: @PostMapping
Mono<User> save(@RequestBody User user) {
log.info("save request arrived");
return Mono.just(user)
.flatMap(user -> saveUser(user));
}
private Mono<User> saveUser(User user) {
return Mono.fromCallable(() -> {
final User userMono = userRepository.save(user);
log.info("user saved!");
return userMono;
}).subscribeOn(Schedulers.boundedElastic());
}
此外,使用由您可以控制和監視的線程池支持的調度程序也是個好主意。 恕我直言,一個經驗法則是為每個資源使用一個專用線程池。 因此,例如 1 個用於 Postgres DB 的線程池,1 個用於 google API(REST 調用)的線程池和 1 個用於 GitHub API 的線程池。這是為什么呢? 如果這些資源中的任何一個出現問題(例如,它將在一定時間內不可用),那么在其他線程池上運行的代碼路徑將不會被阻塞,您的應用程序將繼續運行,至少對於某些代碼路徑而言。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.