spring - Spring Webflux 性能测试抛出 PoolAcquirePendingLimitException
问题描述
我正在尝试学习 Spring webflux。我编写了以下代码来测试反应式编程的性能。这是我的一项服务的控制器:
@RestController
public class PlayerController {
@Autowired
private PlayerRepository playerRepository;
@GetMapping("/players/{id}")
public Mono<Player> getPlayerById(@PathVariable int id) {
return playerRepository.findById(id);
}
型号类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Player {
@Id
private Integer id;
private String name;
private Integer age;
}
存储库:
@Repository
public interface PlayerRepository extends ReactiveCrudRepository<Player, Integer> {}
以下是调用上述服务然后进行数据库调用然后检查它们是否返回相同数据的客户端。客户端的存储库和模型是相同的。
@RestController
public class PlayerController {
@Autowired
private PlayerRepository playerRepository;
@Autowired
private WebClient webClient;
@GetMapping("/players/{id}")
public Mono<Response> getPlayerById(@PathVariable int id) {
LocalDateTime start = LocalDateTime.now();
Mono<Player> playerExternal = webClient.get().uri("/players/{id}", id).retrieve().bodyToMono(Player.class);
Mono<Player> playerDB = playerRepository.findById(2);
Mono<Response> result = playerExternal.zipWith(playerDB, (ext, db) -> {
Response response = new Response();
response.setFlag(ext.getId() == db.getId());
LocalDateTime end = LocalDateTime.now();
response.setTimeTaken(end.from(start).until(end, ChronoUnit.MILLIS) + " ms");
return response;
});
return result;
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>reactive-spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>reactive-spring</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>dev.miku</groupId>
<artifactId>r2dbc-mysql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
客户端运行在8080端口,调用服务运行在9090端口。我使用的是spring boot 2.5.0。我也在使用 jmeter 来模拟 10000 个并发请求。在执行 jmeter 测试计划时,我收到以下异常,
org.springframework.web.reactive.function.client.WebClientRequestException: Pending acquire queue has reached its maximum size of 1000; nested exception is reactor.netty.internal.shaded.reactor.pool.PoolAcquirePendingLimitException: Pending acquire queue has reached its maximum size of 1000
at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:141) ~[spring-webflux-5.3.7.jar:5.3.7]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ Request to GET http://localhost:9090/players/1 [DefaultWebClient]
|_ checkpoint ⇢ Handler com.example.demo.controller.PlayerController#getPlayerById(int) [DispatcherHandler]
|_ checkpoint ⇢ HTTP GET "/players/1" [ExceptionHandlingWebHandler]
Stack trace:
at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:141) ~[spring-webflux-5.3.7.jar:5.3.7]
at reactor.core.publisher.MonoErrorSupplied.subscribe(MonoErrorSupplied.java:70) ~[reactor-core-3.4.6.jar:3.4.6]
at reactor.core.publisher.Mono.subscribe(Mono.java:4150) ~[reactor-core-3.4.6.jar:3.4.6]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.6.jar:3.4.6]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:221) ~[reactor-core-3.4.6.jar:3.4.6]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:221) ~[reactor-core-3.4.6.jar:3.4.6]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:221) ~[reactor-core-3.4.6.jar:3.4.6]
at reactor.core.publisher.MonoNext$NextSubscriber.onError(MonoNext.java:93) ~[reactor-core-3.4.6.jar:3.4.6]
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onError(MonoFlatMapMany.java:204) ~[reactor-core-3.4.6.jar:3.4.6]
如果我需要提供完整的堆栈跟踪,请告诉我。如果我在做任何我不应该做的事情,请告诉我。我也可以分享 jmeter 测试结果。我看到很多请求都失败了,其中大多数都需要很长时间(范围在 1 秒到 18 秒之间)才能响应。
解决方案
默认情况下WebClient
使用连接池运行。池的默认设置是最多 500 个连接和最多 1000 个待处理请求。您已经JMeter
并尝试模拟 10000,但您没有指定如何分配负载。您可能需要增加最大挂起请求数。看看这个文档和这个文档。
如果要配置,WebClient
则需要:
@Bean
public ReactorResourceFactory resourceFactory() {
ConnectionProvider provider =
ConnectionProvider.builder("test")
.maxConnections(500)
// Set custom max pending requests
.pendingAcquireMaxCount(...)
.build();
ReactorResourceFactory factory = new ReactorResourceFactory();
factory.setUseGlobalResources(false);
factory.setConnectionProvider(provider);
return factory;
}
@Bean
public WebClient webClient() {
Function<HttpClient, HttpClient> mapper = client -> {
// Further customizations...
};
ClientHttpConnector connector =
new ReactorClientHttpConnector(resourceFactory(), mapper);
return WebClient.builder().clientConnector(connector).build();
}
推荐阅读
- tensorflow - 更改 vggface 预保留模型的输入大小
- angular - 当我更新了角度版本 7.0 -> 8.0。不更改 tsconfig.json 文件上的目标
- spring - 注释@Value 在我的服务中不起作用
- python-3.x - 加快移动平均计算
- node.js - 如何在后端发送的前端中获取贝宝结帐链接
- python - 在图中查找循环会导致空数组
- node.js - npm install 不下载最新的包
- java - JavaFX 组合框应该何时触发其 onAction?
- azure-api-management - 保护消费 API 管理背后的免费 API 应用服务
- reactjs - 用于条件道具的 TypeScript 实用程序类型(基于类型中其他属性的输入值)