我正在開發幾個具有傳統模式的每個請求執行緒模式的 spring-boot 應用程式。我們正在使用 Spring-boot-webflux 來獲取 WebClient 以在應用程式之間執行我們的 RESTful 集成。因此,我們的應用程式設計要求我們在收到回應后立即阻止發布者。
最近,我們一直在討論是否在我們原本阻塞的應用程式設計中使用回應式模塊不必要地花費資源。據我了解,WebClient 通過分配一個作業執行緒來執行事件回圈中的反應性操作,從而利用了事件回圈。.block()因此,在分配另一個執行緒來執行 http 請求時,使用 webclient會使原始執行緒休眠。與替代的 RestTemplate 相比,WebClient 似乎會通過使用事件回圈來花費額外的資源。
以這種方式部分引入 spring-webflux 會導致額外的資源消耗,而不會對性能產生任何積極的貢獻,無論是單執行緒還是并發,這是否正確?我們不期望將我們當前的堆疊升級為完全反應式,因此逐步升級的論點不適用。
uj5u.com熱心網友回復:
在該團隊的演示文稿 Rossen Stoyanchev中,Spring解釋了其中一些要點。
WebClient將使用有限數量的執行緒(在我的本地計算機上每個內核總共 2 個12 threads)來處理應用程式中的所有請求及其回應。因此,如果您的應用程式接收100 requests并為每個外部服務器發出一個請求,WebClient將以non-blocking/asynchronous方式處理所有使用這些執行緒的請求。
當然,正如您所提到的,一旦您呼叫block原始執行緒就會阻塞,因此112 threads處理這些請求的總數將是 100 個執行緒 12 個執行緒。但是請記住,這 12 個執行緒的大小不會隨著您發出更多請求而增長,并且它們不會執行 I/O 繁重的作業,因此它不像WebClient生成執行緒來實際執行請求或讓它們忙于執行緒每請求時尚。
我不確定執行緒??在block其下的行為是否與通過阻塞呼叫時的行為相同RestTemplate- 在我看來,前者執行緒應該inactive等待NIO呼叫完成,而后者執行緒應該是處理I/O作業,所以也許那里有區別。
如果您開始使用這些reactor好東西會很有趣,例如處理相互依賴的請求,或者并行處理許多請求。然后WebClient肯定會獲得優勢,因為它將使用相同的 12 個執行緒執行所有并發操作,而不是每個請求使用一個執行緒。
例如,考慮這個應用程式:
@SpringBootApplication
public class SO72300024 {
private static final Logger logger = LoggerFactory.getLogger(SO72300024.class);
public static void main(String[] args) {
SpringApplication.run(SO72300024.class, args);
}
@RestController
@RequestMapping("/blocking")
static class BlockingController {
@GetMapping("/{id}")
String blockingEndpoint(@PathVariable String id) throws Exception {
logger.info("Got request for {}", id);
Thread.sleep(1000);
return "This is the response for " id;
}
@GetMapping("/{id}/nested")
String nestedBlockingEndpoint(@PathVariable String id) throws Exception {
logger.info("Got nested request for {}", id);
Thread.sleep(1000);
return "This is the nested response for " id;
}
}
@Bean
ApplicationRunner run() {
return args -> {
Flux.just(callApi(), callApi(), callApi())
.flatMap(responseMono -> responseMono)
.collectList()
.block()
.stream()
.flatMap(Collection::stream)
.forEach(logger::info);
logger.info("Finished");
};
}
private Mono<List<String>> callApi() {
WebClient webClient = WebClient.create("http://localhost:8080");
logger.info("Starting");
return Flux.range(1, 10).flatMap(i ->
webClient
.get().uri("/blocking/{id}", i)
.retrieve()
.bodyToMono(String.class)
.doOnNext(resp -> logger.info("Received response {} - {}", I, resp))
.flatMap(resp -> webClient.get().uri("/blocking/{id}/nested", i)
.retrieve()
.bodyToMono(String.class)
.doOnNext(nestedResp -> logger.info("Received nested response {} - {}", I, nestedResp))))
.collectList();
}
}
如果您運行這個應用程式,您可以看到所有 30 個請求都立即由相同的 12 個(在我的計算機中)執行緒并行處理。Neat!如果您認為可以從邏輯中的這種并行性中受益,那么嘗試一下可能是值得WebClient的。
如果不是,雖然鑒于上述原因,我實際上不會擔心“額外的資源支出”,但我認為為此添加整個reactor/webflux依賴項是不值得的——除了額外的包袱,在日常運營中推理和除錯RestTemplate和thread-per-request模型應該要簡單得多。
當然,正如其他人所提到的,您應該運行負載測驗以獲得適當的指標。
uj5u.com熱心網友回復:
根據RestTemplate的 Spring 官方檔案,它處于維護模式,未來版本可能不支持。
從 5.0 開始,該類處于維護模式,只有較小的更改請求和錯誤被接受。請考慮使用
org.springframework.web.reactive.client.WebClient具有更現代 API 并支持同步、異步和流式處理的方案
至于系統資源,它確實取決于您的用例,我建議運行一些性能測驗,但似乎對于使用阻塞客戶端的低作業負載來說,由于每個連接都有一個專用執行緒,它可能會獲得更好的性能。隨著負載的增加,NIO 客戶端的性能往往會更好。
uj5u.com熱心網友回復:
好問題。
上周我們考慮從 resttemplate 遷移到 webclient。本周,我開始測驗阻塞的 webclient 和 resttemplate 之間的性能,令我驚訝的是,resttemplate 在回應負載很大的場景中表現更好。差異相當大,resttemplate 的回應時間不到一半,使用的資源也更少。
我仍在進行性能測驗,現在我開始向更廣泛的用戶請求測驗。
該應用程式是 mvc,使用的是 spring 5.13.19 和 spring boot 2.6.7。
對于性能測驗,我使用 jmeter 和健康檢查 visualvm/jconsole
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/480052.html
標籤:爪哇 弹簧靴 表现 spring-webflux 弹簧网络客户端
