02.29 springcloud feign优化

在默认情况下 spring cloud feign在进行各个子服务之间的调用时,http组件使用的是jdk的HttpURLConnection,没有使用线程池。源码分析feign的http组件对象生成的过程,然后通过为feign配置http线程池优化调用效率。

我们分析源码spring cloud feign。在spring-cloud-netflix-core/META-INF/spring.factories中可以看到,在spring boot自动配置会初始化FeignRibbonClientAutoConfiguration,这个类会生成Ribbon的使用http组件。

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

分析配置类是FeignRibbonClientAutoConfiguration下面分析此类import的3个类:HttpClientFeignLoadBalancedConfiguration,OkHttpFeignLoadBalancedConfiguration,DefaultFeignLoadBalancedConfiguration

<code>@Import({ HttpClientFeignLoadBalancedConfiguration.class,    OkHttpFeignLoadBalancedConfiguration.class,    DefaultFeignLoadBalancedConfiguration.class })public class FeignRibbonClientAutoConfiguration { …}/<code>

HttpClientFeignLoadBalancedConfiguration为feigin配置appache client的线程池当引入ApacheHttpClient.class类时,会初始化这个配置类方法feignClient()中:根据@ConditionalOnMissingBean(Client.class)知道如果有HttpClient 对象,则创建的ApacheHttpClient使用自己定义的HttpClient 。如果没有,则使用默认值。最后生成LoadBalancerFeignClient对象

<code>@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);    }}/<code>

OkHttpFeignLoadBalancedConfiguration为feigin配置OkHttp,类似apache httpclient, 这里略。DefaultFeignLoadBalancedConfiguration为feigin配置HttpURLConnection,方法feignClient():只有以上两个Client没有生产对象时,才在这个方法中使用Client.Default生成LoadBalancerFeignClient

<code>@Configurationclass DefaultFeignLoadBalancedConfiguration {    @Bean    @ConditionalOnMissingBean    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,          SpringClientFactory clientFactory) {        return new LoadBalancerFeignClient(new Client.Default(null, null),            cachingFactory, clientFactory);    }}/<code>

查看Client.Default的源码,Default 使用HttpURLConnection 建立连接且每次请求都建立一个新的连接

<code> 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();    }   ….}/<code>

综上所述,在默认情况下,spring cloud 没有引入httpclient和okhttp的jar包,所有默认使用HttpURLConnection

1. 替换OKHttp

由此可见feigin优化需要引入线程池有2种可选的线程池:HttpClient和OKHttp比较推荐OKHttp,请求封装的非常简单易用,性能也很ok。

1.1. 添加依赖

<code><dependency>    <groupid>com.squareup.okhttp3/<groupid>    <artifactid>okhttp/<artifactid>/<dependency>/<code>

1.2. 修改配置文件

<code>feign:  okhttp:    enabled: true  httpclient:    enabled: false    max-connections: 1000    max-connections-per-route: 100/<code>

max-connections:最大连接数max-connections-per-route:每个url的连接数

2. 开启Feign请求响应压缩

开启压缩可以有效节约网络资源,但是会增加CPU压力,建议把最小压缩的文档大小适度调大一点

<code>## 开启Feign请求响应压缩feign.compression.request.enabled=truefeign.compression.response.enabled=true## 配置压缩文档类型及最小压缩的文档大小feign.compression.request.mime-types=text/xml,application/xml,application/jsonfeign.compression.request.min-request-size=2048/<code>

三、Ribbon参数调优

主要调整请求的超时时间,是否重试

假如业务没有做幂等性的话建议把重试关掉ribbon.MaxAutoRetriesNextServer=0

<code>## 从注册中心刷新servelist的时间 默认30秒,单位msribbon.ServerListRefreshInterval=15000## 请求连接的超时时间 默认1秒,单位msribbon.ConnectTimeout=30000## 请求处理的超时时间 默认1秒,单位msribbon.ReadTimeout=30000## 对所有操作请求都进行重试,不配置这个MaxAutoRetries不起作用 默认false#ribbon.OkToRetryOnAllOperations=true## 对当前实例的重试次数 默认0#ribbon.MaxAutoRetries=1## 切换实例的重试次数 默认1ribbon.MaxAutoRetriesNextServer=0/<code> 

如果MaxAutoRetries=1和MaxAutoRetriesNextServer=1请求在1s内响应,超过1秒先同一个服务器上重试1次,如果还是超时或失败,向其他服务上请求重试1次。那么整个ribbon请求过程的超时时间为:ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1)

ribbon fegin第一次请求慢问题

开启ribbon饥饿模式

<code>ribbon:    eager-load:    enabled: true /<code>

feigin 日志输出

<code>package com.open.capacity.server.config;import org.springframework.context.annotation.Bean;import feign.Logger.Level;public class GolbalFeignConfig {@Beanpublic Level levl(){return Level.FULL;}}/<code>
<code>@EnableLogging@EnableDiscoveryClient@SpringBootApplication@EnableFeignClients(defaultConfiguration=GolbalFeignConfig.class)public class AuthServerApp {public static void main(String[] args) {//固定端口启动//SpringApplication.run(OpenAuthServerApp.class, args);//随机端口启动SpringApplication app = new SpringApplication(AuthServerApp.class);        app.addListeners(new PortApplicationEnvironmentPreparedEventListener());        app.run(args);}}/<code>
<code>##feign参数优化feign:  client:    config:       default:          loggerLevel: full  ## 配合logging.level=trace debug用于开发调式日志logging:  level:    com.open.capacity: TRACE    org.hibernate: INFO    org.hibernate.type.descriptor.sql.BasicBinder: TRACE    org.hibernate.type.descriptor.sql.BasicExtractor: TRACE/<code>


分享到:


相關文章: