本文基於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類