java Practical Proper Use of RestTemplate under High Concurrency
- 2021-11-30 00:09:32
- OfStack
Preface
If the java project has an http interface that calls the third party, we can use RestTemplate to access it remotely. It also supports configuring connection timeout and response timeout, configuring various long connection strategies, and supporting long connection preheating. Under high concurrency, reasonable configuration and use can effectively improve the response time of the third party interface.
1. What is RestTemplate?
RestTemplate is a client provided by Spring for accessing Rest services, and RestTemplate provides a variety of convenient methods for accessing remote Http services, which can greatly improve the writing efficiency of clients.
2. How to use
1. Create an bean
The following code is simple to configure, only setting the connection timeout and response timeout
/**
* restTemplate Configure
*
* @author Songsong
* @date 2020-08-17 15:09
*/
@Configuration
public class RestTemplateConfiguration {
@Bean(name = "restTemplate")
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// Set the connection timeout 1s
factory.setConnectTimeout(1000);
// Set the read time 1s
factory.setReadTimeout(1000);
return new RestTemplate(factory);
}
}
2. Use steps
Inject in using @ Resource or @ Autowired where you need to
@Resource
private RestTemplate restTemplate;
Then we usually call the interface of the third party is get mode and post mode. restTemplate provides getForEntity and postForEntity methods to support these two modes, which can be called directly. The source code is as follows:
getForEntity method:
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = this.acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
return (ResponseEntity)nonNull(this.execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
postForEntity method:
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = this.httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
return (ResponseEntity)nonNull(this.execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));
}
There are many above two other overloaded methods in the source code, which are the most used in the author's usual project. The parameters are url (the third party http link), request is the required parameters for the request, and responseType is a generic type in the return type.
You only need to parse the returned parameters.
3. RestTemplate usage with high concurrency
In normal development, the above simple configuration may be enough, but under high concurrency, the interface response time is very high, so we need to improve the response time of the third-party interface as much as possible. httpClient long connection can be used in RestTemplate. For the introduction of httpClient long connection, we can refer to: HTTPclient keeps long connection
In the following code, we set the function of long connection warm-up and the number of routing concurrency:
@Slf4j
@Configuration
public class RestTemplateConfiguration {
@Bean(name = "restTemplate")
public RestTemplate restTemplate() {
return getRestTemplate(3, "https://www.baidu.com/......");
}
private RestTemplate getRestTemplate(int maxTotal, String preHeatUrl) {
HttpComponentsClientHttpRequestFactory httpRequestFactory = httpComponentsClientHttpRequestFactory(maxTotal);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
// It takes a long time to solve the first warm-up
if (StringUtils.isNotEmpty(preHeatUrl)) {
try {
restTemplate.postForEntity(preHeatUrl, "", String.class);
} catch (Exception e) {
log.error("preHeat url error:{}", e.getMessage());
}
}
return restTemplate;
}
/**
* ClientHttpRequestFactory Another of the interface 1 Three implementations (recommended), namely:
* HttpComponentsClientHttpRequestFactory Underlying usage Httpclient Connection pooling is created in the way Http Connection request
*
* @return
*/
private HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(int maxTotal) {
//Httpclient Connection pooling, long connection retention time
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(1, TimeUnit.HOURS);
// Set the total number of connections
connectionManager.setMaxTotal(maxTotal);
// Set the concurrency number of the same route
connectionManager.setDefaultMaxPerRoute(maxTotal);
// Settings header
List<Header> headers = new ArrayList<Header>();
headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04"));
headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate"));
headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"));
headers.add(new BasicHeader("Connection", "keep-alive"));
// Create HttpClient
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultHeaders(headers)
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) // Set the number of retries
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) // Set to keep long connections
.build();
// Create HttpComponentsClientHttpRequestFactory Instances
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(httpClient);
// Set the timeout for establishing a connection between the client and the server
requestFactory.setConnectTimeout(10000);
// Set the timeout for the client to read data from the server
requestFactory.setReadTimeout(5000);
// Set the timeout for getting connections from the connection pool, which should not be too long
requestFactory.setConnectionRequestTimeout(2000);
// Buffer request data, default to true . Pass POST Or PUT When sending a large amount of data, it is recommended to change this to false So as not to run out of memory
requestFactory.setBufferRequestBody(false);
return requestFactory;
}
STEP 1 Set up the warm-up function
We can see that in the getRestTemplate method,
return restTemplate ;
I requested it once before, That is to say, when service layer injection needs to be called by the third-party interface, it is called once in advance. According to the characteristics of long connection, the first connection takes a long time. After use, this connection will not be recycled immediately, and it will still survive at a fixed time. Therefore, under high concurrency, the response time of the preheated interface will be greatly improved.
2. Set the number of maxtotal reasonably
We can see the following code
// Set the total number of connections
connectionManager.setMaxTotal(maxTotal);
We can see this line 1, maxTotal sets the total number of connections, This setting needs to be set according to the response time of the interface and the QPS that needs to be supported. For example, if the interface response time is 100ms and the QPS to be supported is 5000, that is, 5000/s, then a long connection 1s can handle 10 requests, and a total of 500 maxTotal are required, which is the approximate number of settings, but sometimes QPS is not so stable, so the specific settings depend on the specific situation.
RestTemplate depth analysis can refer to: RestTemplate depth analysis