首页 > 其他分享 >OpenFeign的9个坑,每个都能让你的系统奔溃

OpenFeign的9个坑,每个都能让你的系统奔溃

时间:2024-01-23 11:57:56浏览次数:28  
标签:feign 每个 OpenFeign 重试 复制 超时 奔溃 ribbon

 

OpenFeign是SpringCloud中的重要组件,它是一种声明式的HTTP客户端。使用OpenFeign调用远程服务就像调用本地方法一样,但是如果使用不当,很容易踩到坑。

坑一:用对Http Client

1.1 feign中http client

如果不做特殊配置,OpenFeign默认使用jdk自带的HttpURLConnection,我们知道HttpURLConnection没有连接池、性能和效率比较低,如果采用默认,很可能会遇到性能问题导致系统故障。

可以采用Apache HttpClient,properties文件中增加下面配置:

feign.httpclient.enabled=true

pom文件中增加依赖:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>9.3.1</version>
</dependency>

也可以采用OkHttpClient,properties文件中增加下面配置:

feign.okhttp.enabled=true

pom文件中增加依赖:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>10.2.0</version>
</dependency>

1.2 ribbon中的Http Client

通过OpenFeign作为注册中心的客户端时,默认使用Ribbon做负载均衡,Ribbon默认也是用jdk自带的HttpURLConnection,需要给Ribbon也设置一个Http client,比如使用okhttp,在properties文件中增加下面配置:

ribbon.okhttp.enabled=true

坑二:全局超时时间

OpenFeign可以设置超时时间,简单粗暴,设置一个全局的超时时间,如下:

feign.client.config.default.connectTimeout=2000
feign.client.config.default.readTimeout=60000

如果不配置超时时间,默认是连接超时10s,读超时60s,在源码feign.Request的内部类Options中定义。

这个接口设置了最大的readTimeout是60s,这个时间必须大于调用的所有外部接口的readTimeout,否则处理时间大于readTimeout的接口就会调用失败。

如下图,在一个系统中使用OpenFeign调用外部三个服务,每个服务提供两个接口,其中serviceC的一个接口需要60才能返回,那上面的readTimeout必须设置成60s。

但是如果serviceA出故障了,表现是接口1超过60s才能返回,这样OpenFeign只能等到读超时,如果调用这个接口的并发量很高,会大量占用连接资源直到资源耗尽系统奔溃。要防止这样的故障发生,就必须保证接口1能fail-fast。最好的做法就是给serviceC单独设置超时时间。

坑三:单服务设置超时时间

从上一节的讲解我们看到,需要对serviceC单独设置一个超时时间,代码如下:

feign.client.config.serviceC.connectTimeout=2000
feign.client.config.serviceC.readTimeout=60000

这个时间会覆盖第一节中默认的超时时间。但是问题又来了,serviceC中又掉了serviceD,因为serviceD的故障导致接口6发生了读超时的情况,为了不让系统奔溃,不得不对serviceC的接口5单独设置超时时间。如下图:

坑四:熔断超时时间

怎样给单个接口设置超时时间,查看网上资料,必须开启熔断,配置如下:

feign.hystrix.enabled=true

开启熔断后,就可以给单个接口配置超时了。如果调用serviceC的接口5的声明如下:

@FeignClient(value = "serviceC"configuration = FeignMultipartSupportConfig.class)
public interface ServiceCClient {
    @GetMapping("/interface5")
    String interface5(String param);
}

根据上面interface5接口的声明,在properties文件中增加如下配置:

hystrix.command.ServiceCClient#interface5(param).execution.isolation.thread.timeoutInMilliseconds=60000

网上资料说的并不准确,这个超时时间并没有起作用。为什么不生效呢?

4.1 使用feign超时

最终使用的超时时间来自于Options类。如果我们配置了feign的超时时间,会选择使用feign超时时间,下面代码在FeignClientFactoryBean类的configureUsingProperties方法:

if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
 builder.options(new Request.Options(config.getConnectTimeout(), config.getReadTimeout()));
}

4.2 使用ribbon超时

如果没有配置feign,但是配置了ribbon的超时时间,会使用ribbon的超时时间。我们看下这段源代码,FeignLoadBalancer里面的execute方法,

public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
  throws IOException {
 Request.Options options;
 if (configOverride != null) {
  RibbonProperties override = RibbonProperties.from(configOverride);
  options = new Request.Options(
    override.connectTimeout(this.connectTimeout),
    override.readTimeout(this.readTimeout));
 }
 else {
  options = new Request.Options(this.connectTimeout, this.readTimeout);
 }
 //这个request里面的client就是OkHttpClient
 Response response = request.client().execute(request.toRequest(), options);
 return new RibbonResponse(request.getUri(), response);
}

4.3 使用自定义Options

对于单个接口怎么配置超时时间,我这里给出一个方案,如果你有其他方案,欢迎探讨。我的方案是使用RestTemplate来调这个接口,单独配置超时时间,配置代码如下,这里使用OkHttpClient:

public class RestTemplateConfiguration {
 
    @Bean
    public OkHttp3ClientHttpRequestFactory okHttp3RequestFactory(){
        OkHttp3ClientHttpRequestFactory requestFactory = new OkHttp3ClientHttpRequestFactory();
        requestFactory.setConnectTimeout(2000);
        requestFactory.setReadTimeout(60000);
        return requestFactory;
    }
 
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(OkHttp3ClientHttpRequestFactory okHttp3RequestFactory){
        return new RestTemplate(okHttp3RequestFactory);
    }
}

为了使用ribbon负载均衡,上面加了@LoadBalanced

如果使用RestTemplate,就会使用OkHttp3ClientHttpRequestFactory中配置的时间。

坑五:ribbon超时时间

作为负载均衡,ribbon超时时间也是可以配置的,可以在properties增加下面配置:

ribbon.ConnectTimeout=2000
ribbon.ReadTimeout=11000

有文章讲ribbon配置的超时时间必须要满足接口响应时间,其实不然,配置feign的超时时间就足够了,因为它可以覆盖掉ribbon的超时时间。

坑六:重试默认不开启

OpenFeign默认是不支持重试的,可以在源代码FeignClientsConfiguration中feignRetryer中看出。


@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
 return Retryer.NEVER_RETRY;
}

要开启重试,我们可以自定义Retryer,比如下面这行代码:

Retryer retryer = new Retryer.Default(100, 1000, 2);

表示每间隔100ms,最大间隔1000ms重试一次,最大重试次数是1,因为第三个参数包含了第一次请求。

坑七:Ribbon重试

7.1 拉取服务列表

Ribbon默认从服务端拉取列表的时间间隔是30s,这个对优雅发布很不友好,一般我们会把这个时间改短,如下改成3s:

serviceC.ribbon.ServerListRefreshInterval=3

7.2 重试

Ribbon重试有不少需要注意的地方,这里分享4个。

1.同一实例最大重试次数,不包括首次调用,配置如下:

serviceC.ribbon.MaxAutoRetries=1

这个次数不包括首次调用,配置了1,重试策略会先尝试在失败的实例上重试一次,如果失败,请求下一个实例。

2.同一个服务其他实例的最大重试次数,这里不包括第一次调用的实例。默认值为1:

serviceC.ribbon.MaxAutoRetriesNextServer=1

3.是否对所有操作都重试,如果改为true,则对所有操作请求都进行重试,包括post,建议采用默认配置false。

serviceC.ribbon.OkToRetryOnAllOperations=false

4.对指定的http状态码进行重试

serviceC.retryableStatusCodes=404,408,502,500

坑八:hystrix超时

如下图:

hystrix默认不开启,但是如果开启了hystrix,因为hystrix是在Ribbon外面,所以超时时间需要符合下面规则:hystrix超时 >= (MaxAutoRetries + 1) * (ribbon ConnectTimeout + ribbon ReadTimeout)

如果Ribbon不重试,MaxAutoRetries=0

根据上面公式,假如我们配置熔断超时时间如下:

hystrix.command.ServiceCClient#interface5(param).execution.isolation.thread.timeoutInMilliseconds=15000
ribbon.ReadTimeout=8000

这个配置是不会重试一次的。serviceA调用serviceB时,hystrix会等待Ribbon返回的结果,如果Ribbon配置了重试,hystrix会一直等待直到超时。上面的配置,因为第一次请求已经耗去了8s,剩下时间7s不够请求一次了,所以是不会进行重试的。

坑九:使用OpenFeign做http客户端

即使不用注册中心,使用OpenFeign做普通http客户端也是很方便的,但是有三点需要注意:

  • 不用配置ribbon相关参数
  • 使用RestTemplate调用时,不考虑负载均衡
  • 使用过程中OpenFeign要组装出自己的一套请求,跟直接使用http客户端比,会有一定开销

使用OpenFeign有很多配置上的坑,对于没有注册中心的情况,建议直接使用http客户端

https://cloud.tencent.com/developer/article/1866274

 

标签:feign,每个,OpenFeign,重试,复制,超时,奔溃,ribbon
From: https://www.cnblogs.com/softidea/p/17981994

相关文章

  • 若依框架解读(微服务版)——2.模块间的调用逻辑(ruoyi-api模块)(OpenFeign)(@innerAuth)
    模块之间的关系我们可以了解到一共有这么多服务,我们先启动这三个服务其中rouyi–api模块是远程调用也就是提取出来的openfeign的接口ruoyi–commom是通用工具模块其他几个都是独立的服务ruoyi-api模块api模块当中有几个提取出来的OpenFeign的接口分别为文件,日志,用户服务......
  • 【解决方案】如何使用 Http API 代替 OpenFeign 进行远程服务调用
    目录前言一、何为OpenFeign1.1@FeignClient注解1.2注意事项二、常见的HttpAPI2.1Apache2.2Okhttp2.3Hutool三、RestTemplate3.1详解.execute()四、文章小结前言看到标题大家可能会有点疑惑吧:OpenFeign不是挺好用的吗?尤其是微服务之间的远程调用,平时用的也挺习惯的,为啥要替换呢......
  • abc等多个系统 每个系统有多个文档 ,每个系统根据不同的文类型获取该文件类型最新上传
    假如有abc等多个系统每个系统有多个文档,每个系统根据不同的文类型获取该文件类型最新上传时间文档(文件类型(文件类型字段为idoctype)分别为设计文档和评审记录文档,最新上传时间字段为duptime)这个思路和Java代码list怎莫处理对于这个问题,可以使用一个嵌套的Map来处理。外层的M......
  • 分割和跟踪每个像素(STEP)评估
    分割和跟踪每个像素(STEP)评估SegmentingandTrackingEveryPixel(STEP)Evaluationhttps://www.cvlibs.net/datasets/kitti/eval_step.php此基准是ICCV21研讨会的一部分:分割和跟踪每个点和像素。分段和跟踪每个像素(STEP)基准由21个训练序列和29个测试序列组成。它基于KITTI跟......
  • 每个Go程序员必犯之错之切片循环错误
    每个Go程序员必犯之错原创 晁岳攀(鸟窝) 鸟窝聊技术 2023-12-1808:48 发表于北京 听全文说起每个程序员必犯的错误,那还得是"循环变量"这个错误了,就连Go的开发者都犯过这个错误,这个错误在Go的FAQ中也有提到Whathappenswithclosuresrunningasgoroutines?[......
  • ABC 等多个系统 每个系统下有多个附件 ,每个系统获取自己最新日期的文档
    1.假如有ABC等多个系统每个系统下有多个附件,每个系统获取自己最新日期的文档(每个文件都标有最新日期duptime)Java代码从表中查询出的list怎莫处理得到每个系统下面最新的文件Map<String,List<Attachment>>attachmentsBySystem=newHashMap<>();//对每个附件进行遍......
  • 【OpenFeign】【使用问题】OpenFeign 里如何调用 form-data 接口或者 MultipartFile
    1 前言今儿有个需求涉及到文件上传的东西,关键是OpenFeign去调用,当然最后底牌我也可以创建普通的HTTP请求或者RestTemplate自己请求是不是也行,但是本人这个倔驴型性格,偶尔也会跟自己犟犟,就是要用OpenFeign把它搞出来。首先我有两个这样的接口://客户导入接口@PostMa......
  • openfeign 忽略ssl证书 亲测有效
    请求https接口异常Causedby:javax.net.ssl.SSLHandshakeException:PKIXpathbuildingfailed:sun.security.provider.certpath.SunCertPathBuilderException:unabletofindvalidcertificationpathtorequestedtarget atjava.base/sun.security.ssl.Alert.createSSL......
  • 随机生成每个日期的时分秒,同天的累计,略过12-14点
    <?php//洛杉矶时区date_default_timezone_set('America/Los_Angeles');$date_arr=['2023-11-10','2023-11-10','2023-11-10','2023-11-11','2023-11-11','2023-11-12�......
  • 2023 年精选:每个 DevOps 团队都应该了解的 5 种微服务设计模式
    微服务彻底改变了应用程序开发世界,将大型整体系统分解为更小、更易于管理的组件。这种架构风格的特点是独立、松散耦合的服务,带来了从可扩展性、模块化到更高的灵活性等众多优势。DevOps团队如何最好地利用这种方法来实现最高效率?答案在于理解并有效地采用微服务设计模式。在本文......