java Practical Proper Use of RestTemplate under High Concurrency

  • 2021-11-30 00:09:32
  • OfStack

Directory Preface 1. What is RestTemplate? 2. How to use 1. Create an bean 2. Use Step 3. Use RestTemplate under high concurrency 1. Set warm-up function 2. Set the number of maxtotal reasonably. Summary

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

Summarize


Related articles: