背景
项目中调用第三方接口,第三方接口响应时间不稳定,并且并发越大响应时间越长,如果使用BIO模式可能会导致服务器连接占用过高,所以采用WebClient reactor模式来调用第三方接口。
连接池相关配置
maxConnections:最大连接数,默认最大连接数为处理器数量*2(但最小值为16),最大只能设置为200,超过这个数值设置无效。
pendingAcquireMaxCount:等待队列大小,默认是最大连接数的2倍,等待队列pendingAcquireMaxCount调大,同时处理的任务数等于最大连接数,未被处理的任务在队列中等待处理。
pendingAcquireTimeout:任务等待超时时间,当队列中的任务等待超过pendingAcquireTimeout还获取不到连接,就会抛出异常。
测试代码
@ConfigurationProperties("web.client")
@Data
@Configuration
public class WebClientProperties {
/**
* 超时时间 单位秒
*/
private int pendingAcquireTimeout = 50;
/**
* 最大等待任务数
* */
private int pendingAcquireMaxCount = 10000;
/**
* 连接池最大连接数
*/
private int maxConnections = 1000;
}
@Configuration
public class WebClientConfig {
@Autowired
private WebClientProperties webClientProperties;
@Bean
public WebClient webClient() {
//配置固定大小连接池
ConnectionProvider provider = ConnectionProvider
.builder("tax-core")
// 等待超时时间
.pendingAcquireTimeout(Duration.ofSeconds(webClientProperties.getPendingAcquireTimeout()))
// 最大连接数
.maxConnections(webClientProperties.getMaxConnections())
// 等待队列大小
.pendingAcquireMaxCount(webClientProperties.getPendingAcquireMaxCount())
.build();
HttpClient httpClient = HttpClient.create(provider);
// 使用Reactor
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
}
@RestController
@Slf4j
@RequestMapping
public class WebClientTest {
@Autowired
private WebClient webClient;
AtomicInteger count = new AtomicInteger(1);
Map<Integer, Long> map = new ConcurrentSkipListMap<>();
/**
* 模拟第三方接口
* @param param
* @return
* @throws InterruptedException
*/
@PostMapping("test/client")
public Integer testClient(@RequestBody Param param) throws InterruptedException {
Thread.sleep(10000);
return param.getSerialNo();
}
/**
* 测试接口
* @param integer
* @return
*/
@GetMapping("test/client/get")
public ResponseEntity<String> testClientPost(@RequestParam Integer integer) {
for (int i = 1; i < integer + 1; i++) {
Param param = new Param();
param.setSerialNo(i);
call(param);
}
return new ResponseEntity<>();
}
/**
* 调用第三方接口
* @param param
*/
public void call(Param param) {
final Mono<Integer> monoResp = webClient.post()
.uri(URI.create("http://127.0.0.1:8085/test/client"))
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.body(Mono.just(param), Param.class)
.retrieve()
.bodyToMono(Integer.class);
map.put(param.getSerialNo(), System.currentTimeMillis());
monoResp.subscribe((s) ->
System.out.println("响应流水号:" + s + " 耗时:" + (System.currentTimeMillis() - map.get(s))
+ " 响应次数:" + count.getAndIncrement())
);
}
@Data
public static class Param {
private Integer serialNo;
}
}
调试
请求数大于max-connections
配置调整
web:
client:
pending-acquire-timeout: 30
pending-acquire-max-count: 100
max-connections: 10