1. An overview of the

By default, spring Cloud Feign uses THE JDK’s HttpURLConnection for HTTP components to make calls between sub-services, not thread pools. This article analyzes feign’s HTTP component object generation process from source code, and then optimizes call efficiency by configuring HTTP thread pools for Feign.

2. Source code analysis

We analyzed the source code Spring Cloud Feign. In the spring — cloud – netflix – core/meta-inf/spring. As you can see, in the factories in the spring the boot configuration will initialize FeignRibbonClientAutoConfiguration automatically, This class generates HTTP components for the Ribbon.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.feign.ribbon.FeignRibbonClientAutoConfiguration,\Copy the code

Analysis under the configuration class is FeignRibbonClientAutoConfiguration such import of three categories: HttpClientFeignLoadBalancedConfiguration OkHttpFeignLoadBalancedConfiguration, DefaultFeignLoadBalancedConfiguration

@Import({ HttpClientFeignLoadBalancedConfiguration.class, OkHttpFeignLoadBalancedConfiguration.class, DefaultFeignLoadBalancedConfiguration. Class}) public class FeignRibbonClientAutoConfiguration {... }Copy the code

For configuration of feigin HttpClientFeignLoadBalancedConfiguration appache client thread pool When introducing ApacheHttpClient. Class class, Initializes the configuration class method feignClient() : ConditionalOnMissingBean(client.class) knows that the ApacheHttpClient created uses its own defined HttpClient if it has an HttpClient object. If not, use the default value. Finally, the LoadBalancerFeignClient object is generated

@Configuration @ConditionalOnClass(ApacheHttpClient.class) @ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true) class HttpClientFeignLoadBalancedConfiguration { @Autowired(required = false) private HttpClient httpClient; @Bean @ConditionalOnMissingBean(Client.class) public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,  SpringClientFactory clientFactory) { ApacheHttpClient delegate; if (this.httpClient ! = null) { delegate = new ApacheHttpClient(this.httpClient); } else { delegate = new ApacheHttpClient(); } return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory); }}Copy the code

For configuration of feigin OkHttpFeignLoadBalancedConfiguration OkHttp, similar to the apache httpclient, just here. Method for configuration of feigin DefaultFeignLoadBalancedConfiguration HttpURLConnection, feignClient () : The LoadBalancerFeignClient is generated using client. Default in this method only if the above two clients do not produce objects

@Configuration class DefaultFeignLoadBalancedConfiguration { @Bean @ConditionalOnMissingBean public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) { return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory, clientFactory); }}Copy the code

View the source code for client. Default, which uses HttpURLConnection to establish a connection and establishes a new connection with each request

public static class Default implements Client { @Override public Response execute(Request request, Options options) throws IOException { HttpURLConnection connection = convertAndSend(request, options); return convertResponse(connection).toBuilder().request(request).build(); }... .}Copy the code

To sum up, spring Cloud does not introduce jar packages for HttpClient and OKHTTP by default, all use HttpURLConnection by default

3. Use the Appach HttpClient thread pool

By default, calls between services use HttpURLConnection, which is very inefficient. To improve efficiency, you can improve efficiency through connection pooling. In this section, we use Appache HttpClient as connection pooling. Configuring the OkHttpClient connection pool is a similar method, which is omitted here. After the analysis of the previous section, configure the thread pool method: import appache HttpClient and start the corresponding configuration, and finally need to generate the HttpClient object.

Feign-httpclient.jar was introduced in 3.1.pom.xml

<! <dependency> <groupId> IO. Github. Openfeign </groupId> <artifactId>feign- httpClient </artifactId> </dependency>Copy the code

3.2. Configure the application-hystrix-feign.yml parameter to start httpClient

Feign: hystrix: # Enable Hystrix in Feign. By default, hystrix is disabled. enabled: true okhttp: enabled: falseCopy the code

3.3. Custom configuration classes

Using the configuration class, generate the HttpClient object. Because use PoolingHttpClientConnectionManager connection pool, we need to start the timer, timing recovery of expired connection. For details about the reason for configuring scheduled connection reclamation, see Troubleshooting: HttpClient Connection Pool Failure

@Configuration public class HttpPool { @Bean public HttpClient httpClient(){ System.out.println("init feign httpclient configuration " ); Build requestConfigBuilder = requestConfig.custom (); . / / timeout requestConfigBuilder setSocketTimeout (5 * 1000); . / / connection time requestConfigBuilder setConnectTimeout (5 * 1000); RequestConfig defaultRequestConfig = requestConfigBuilder.build(); / / / / the connection pool configuration long connection final 30 seconds PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS); . / / the total number of connections pollingConnectionManager setMaxTotal (5000); . / / the same way by the number of concurrent pollingConnectionManager setDefaultMaxPerRoute (100); HttpClientBuilder = httpClientBuilder.create (); / / maintain a long connection configuration, need to first add Keep Alive - httpClientBuilder. SetKeepAliveStrategy (new DefaultConnectionKeepAliveStrategy ()); httpClientBuilder.setConnectionManager(pollingConnectionManager); httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig); HttpClient client = httpClientBuilder.build(); // Start the Timer to reclaim expired connections. Timer Timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { // System.out.println("=====closeIdleConnections==="); pollingConnectionManager.closeExpiredConnections(); pollingConnectionManager.closeIdleConnections(5, TimeUnit.SECONDS); }}, 10 * 1000, 5 * 1000); System.out.println("===== Apache httpClient initializes the connection pool ==="); return client; }}Copy the code

3.4. Test:

Start the project: cloud – registration – center, the cloud – service – hystrix startup services: HystrixFeignCloudConsumerApplication perform requests: http://127.0.0.1:12082/hystrix-feign/simple

Configure logging for the debug output (set logback – spring. XML for the debug level), if there are similar to the log output (including PoolingHttpClientConnectionManager), connection pool configuration is successful

2018-04-09 23:11:49. 017 [hystrix - cloud - hystrix - service - 1] DEBUG O.A.H.I.C.P oolingHttpClientConnectionManager - The Connection request: [the route: {} - > http://192.168.0.113:12081] [total kept alive: 0; the route allocated: 0 of 100; total allocated: 0 of 5000] 2018-04-09 23:11:49. 020 [hystrix - cloud - hystrix - service - 1] DEBUG O.A.H.I.C.P oolingHttpClientConnectionManager - the Connection leased: [id: 0] [the route: {} - > http://192.168.0.113:12081] [total kept alive: 0; the route allocated: 1 of 100; total allocated: 1 of 5000]Copy the code

Code 4.

Please use tag V0.12 instead of master as I can’t guarantee that the master code will always be the same