本文基于Spring Boot 2.6.6和Spring Cloud 2021.0.1
一、Spring Cloud Gateway
1.1 client部分
gateway向其他服务发起请求所用的配置,使用的是reactor.netty.http.client.HttpClient。
相关配置都在org.springframework.cloud.gateway.config.HttpClientProperties类中
# 连接超时时间(毫秒)
spring.cloud.gateway.httpclient.connect-timeout=45000
# 请求响应等待时间
spring.cloud.gateway.httpclient.response-timeout=null
# 线程池类型,除了默认的elastic,还支持fixed和disabled
# elastic:无限扩展的线程池
# fixed:固定数量线程池
# disabled:不使用线程池——只有一个线程
spring.cloud.gateway.httpclient.pool.type=elastic
# 最大线程数,只在类型为fixed时有效
spring.cloud.gateway.httpclient.pool.max-connections=CPU核数*2(最小为16)
# 从线程池获取连接的最大等待时间(毫秒)
spring.cloud.gateway.httpclient.pool.acquire-timeout=45000
# 线程空闲多久会被回收(毫秒)
spring.cloud.gateway.httpclient.pool.max-idle-time=null
# 线程最大存活时间(毫秒)
spring.cloud.gateway.httpclient.pool.max-life-time=null
# 定时检测周期(毫秒),检测哪些线程需要被回收
# (1)只有空闲的线程会被回收
# (2)即使未达到max-idle-time,当达到max-life-time时也会被回收
spring.cloud.gateway.httpclient.pool.eviction-interval=null
1.2 server部分
gateway接收请求的部分(请求一般来自于前端),使用的是reactor.netty.http.server.HttpServer。
对应配置org.springframework.boot.autoconfigure.web.ServerProperties#Netty
# 连接超时时间(毫秒)
server.netty.connection-timeout=30000
# 连接等待时间(毫秒),超时会被自动关闭。为空表示永远不关闭,全靠请求方
server.netty.idle-timeout=null
注意,spring boot没有把netty-web-server的线程参数配置开放出来,个人猜测是因为netty调高线程数其实并没有什么作用,如果需要修改的话可以通过以下两种方式:
(1)自行声明ReactorResourceFactory
@Bean
public ReactorResourceFactory reactorServerResourceFactory() {
ReactorResourceFactory reactorResourceFactory = new ReactorResourceFactory();
reactorResourceFactory.setUseGlobalResources(false);
// 设置event loop线程池
reactorResourceFactory.setLoopResources(LoopResources.create("my-http1", 16, true));
// 设置连接池
reactorResourceFactory.setConnectionProvider(ConnectionProvider.create("my-http2", 16));
return reactorResourceFactory;
}
(2)通过设置系统参数或者环境变量的方式
详见reactor.netty.resources.ConnectionProvider和reactor.netty.resources.LoopResources类
# 设置最大连接数,最小为16
-Dreactor.netty.pool.maxConnections=xxx
# 设置IO线程数,最小为4
-Dreactor.netty.ioWorkerCount=xxx
# 设置selector线程数,最小为4
-Dreactor.netty.ioSelectCount=xxx
二、Spring WebFlux
spring cloud gateway server部分本质上就是一个webflux应用,所以相关配置可以直接参考gateway的。
当然有个不同的地方就是WebFlux是可以使用tomcat的,不过既然选择了使用WebFlux的编程模型,一般都会使用netty或者undertow这些,这里就不扩展了。
三、Spring MVC(Tomcat)
# 最大线程数
server.tomcat.threads.max=200
# 最小线程数
# tomcat没有暴露idletime的配置,默认就是60s
# 详情查看org.apache.tomcat.util.net.AbstractEndpoint#createExecutor方法
server.tomcat.threads.min-spare=10
# 对应JDK nio-server的backlog参数,可以简单认为是等待队列的大小
server.tomcat.accept-count=100
# 最大连接数,因为是NIO模型,所以这个值远远大于线程数
server.tomcat.max-connections=8192
# org.apache.coyote.Processor的缓存大小,被缓存的processor会复用之前的request和response对象
server.tomcat.processor-cache=200
# 对应socket的SO_TIMEOUT(毫秒),其实就是连接等待时间
server.tomcat.connection-timeout=20000
# 指的是HTTP中的keep-alive功能(毫秒),在一定时间内http请求会复用tcp连接
server.tomcat.keep-alive-timeout=20000
# 允许keep-alive的最大请求数
server.tomcat.max-keep-alive-requests=200
四、Spring Cloud LoadBalancer
Spring Cloud在2020版本的时候废弃了Netflix-ribbon,改为了自研的Spring Cloud LoadBalancer。
LoadBalancer本身只负责多个服务之间负载均衡的处理,具体的请求是通过对接各种第三方客户端实现的,比如Apache HttpComponents、Okhttp、Reactor Netty等等,具体的配置跟使用LoadBalancer的模块有关(参考下边几个小节)。
五、Feign With LoadBalancer
底层基于Apache HttpComponents 4.x(可以自行切换成其他HTTP框架)。
相关配置见org.springframework.cloud.openfeign.support.FeignHttpClientProperties和org.springframework.cloud.openfeign.FeignClientProperties类
# 建立连接的超时时间(毫秒)
feign.httpclient.connection-timeout=2000
# 定时检测任务周期(毫秒),用来定期清理连接池中过期的连接
feign.httpclient.connection-timer-repeat=3000
# 连接池最大数量
feign.httpclient.max-connections=200
# 单个url的最大连接数量
feign.httpclient.max-connections-per-route=50
# 连接的存活时间(秒)
feign.httpclient.time-to-live=900
# 全局连接超时时间(毫秒)
feign.client.config.default.connect-timeout=10000
# 全局读写超时时间(毫秒)
feign.client.config.default.read-timeout=60000
六、RestTemplate With LoadBalancer
底层基于Apache HttpComponents 4.x(可以自行切换成其他HTTP框架)。
spring自带的org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration配置类是无法对各种超时时间进行配置的,可以通过以下方法修改。
注意:虽然创建CloseableHttpClient 的时候有一个连接超时时间,但是在配置Feign和RestTemplate的时候这个时间会被覆盖掉
@Configuration(proxyBeanMethods = false)
static class RestTemplateConfiguration {
private final Timer connectionManagerTimer = new Timer("HttpClientConfiguration.connectionManagerTimer", true);
private CloseableHttpClient httpClient;
@Autowired(required = false)
private RegistryBuilder registryBuilder;
@Bean
public CloseableHttpClient httpClient(FeignHttpClientProperties httpClientConfig,
ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
ApacheHttpClientFactory httpClientFactory) {
HttpClientConnectionManager connectionManager = connectionManagerFactory.newConnectionManager(
httpClientConfig.isDisableSslValidation(), httpClientConfig.getMaxConnections(),
httpClientConfig.getMaxConnectionsPerRoute(), httpClientConfig.getTimeToLive(),
httpClientConfig.getTimeToLiveUnit(), registryBuilder
);
// 取代HttpComponents自带的过期检查,因为配置不够灵活,详见IdleConnectionEvictor
this.connectionManagerTimer.schedule(new TimerTask() {
@Override
public void run() {
connectionManager.closeExpiredConnections();
}
}, 30000, httpClientConfig.getConnectionTimerRepeat());
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setConnectTimeout(httpClientConfig.getConnectionTimeout())
.setRedirectsEnabled(httpClientConfig.isFollowRedirects())
.build();
this.httpClient = httpClientFactory.createBuilder()
.setDefaultRequestConfig(defaultRequestConfig)
.setConnectionManager(connectionManager)
.build();
return this.httpClient;
}
@PreDestroy
public void destroy() {
this.connectionManagerTimer.cancel();
if (this.httpClient != null) {
try {
this.httpClient.close();
} catch (IOException e) {
log.error("Could not correctly close httpClient.");
}
}
}
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
requestFactory.setConnectTimeout(5 * 1000);
requestFactory.setConnectionRequestTimeout(60 * 1000);
requestFactory.setReadTimeout(30 * 60 * 1000);
return requestFactory;
}
@Bean
public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer restTemplateBuilderConfigurer,
ClientHttpRequestFactory clientHttpRequestFactory) {
RestTemplateBuilder builder = new RestTemplateBuilder();
builder = builder.requestFactory(() -> clientHttpRequestFactory);
return restTemplateBuilderConfigurer.configure(builder);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
七、WebClient With LoadBalancer
参考gateway的server部分自行声明ReactorResourceFactory,不过要保证你的声明早于org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorConfiguration类