feign使用okHttpClient,調用原理


最近項目中 spring cloud 用到http請求,使用feign,配置okhttp,打算配置一下就直接使用,不過在壓測與調優過程中遇到一些沒有預測到的問題,附上排查與解析結

yml、pom配置

feign:
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 3000
        loggerLevel: FULL
  httpclient:
    enabled: false # 關閉 httpclient
  okhttp:
      enabled: true # 開啟 okhttp
<!-- feign-okhttp -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>4.2.2</version>
    <!-- <exclusions> -->
    <!-- 根據情況 -->
    <!-- </exclusions> -->
</dependency>

配置后,http請求沒問題

但在並發量100的場景下壓測時,出現每個http請求相應時間達到100ms的情況,排查下游服務的反應時間很快,推測大量時間消耗在feign發起http請求

懷疑okHttp的負載均衡可能有問題,我的服務發現使用consul,也很好奇okhttp是怎么實現的負載均衡,繼續排查:

 

配置feign配置類

@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) throws NoSuchAlgorithmException, KeyManagementException {
SSLContext ctx = SSLContext.getInstance("SSL");
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
return new LoadBalancerFeignClient(new Client.Default(ctx.getSocketFactory(), (hostname, session) -> {
// TODO Auto-generated method stub
return true;
}), cachingFactory, clientFactory);
}

這里配置使用 LoadBalancerFeignClient,配置后,100並發下效果仍然不佳

經排查,代碼中調用feign就耗費了100ms左右,只能深入看代碼查原因,找一條響應時間長的case,看feign內部時間具體消耗在哪里:

 

 這里clientName為consul配置的服務發現名,比如配置里

feign:
  service:
    order: test-name
在feignClient里配置解析后,這里直接拿到的就是"test-name",然后通過lbClient去請求consul集群,獲取到ip+port
也就是說,okhttpClient不直接支持負載均衡,只是請求的執行者,在其之前由 LoadBalancerFeignClient 獲取實例

 到這里,響應時間都很長,還需要繼續深入

FeignLoadbalancer,在這里可以看出是否實際使用了okhttp:

 

繼續排查,發現發送http請求很快,但最簡單的encode,decode出現時間長的情況

org.springframework.cloud.openfeign.support.SpringDecoder

問題在這里,每次使用http請求,都new HttpMessageConverterExtractor,費時費力,導致並發量高時load、響應時間都高了

解決方案

在feign配置類里,指定decoder,不要每次new

@Bean
public Decoder feignDecoder() {
    ObjectMapper mapper = new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .registerModule(new Jdk8Module())
        //fix LocalDateTime 無法序列化問題
        .registerModule(new JavaTimeModule());
    return new JacksonDecoder(mapper);
}

重新驗證,100並發下響應時間降低到20ms,接近下游服務響應時間,http請求已不是瓶頸

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM