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>


分享到:


相關文章: