作者 | jinjunzhu

来源 | jinjunzhu

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

坑一:用对Http Client

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>
ribbon中的Http Client

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

ribbon.okhttp.enabled=true

坑二:全局超时时间

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

feign.client.config.default.connectTimeout=2000feign.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=2000feign.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

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

使用feign超时

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

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

使用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);}

使用自定义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=2000ribbon.ReadTimeout=11000

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

坑六:重试默认不开启

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

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

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

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

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

坑七:Ribbon重试

拉取服务列表

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

serviceC.ribbon.ServerListRefreshInterval=3

重试

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=15000ribbon.ReadTimeout=8000

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

坑九:使用OpenFeign做http客户端

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

  • 不用配置ribbon相关参数

  • 使用RestTemplate调用时,不考虑负载均衡

  • 使用过程中OpenFeign要组装出自己的一套请求,跟直接使用http客户端比,会有一定开销

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

☞90后字节跳动员工内幕交易获利近5.5万,被罚50万;三七互娱回应外包员工猝死;谷歌推出全新漏洞悬赏平台|极客头条☞IE 退出后,苹果 Safari 成为了开发者最讨厌的浏览器?☞宁做程序员,不做 CTO!估值 50 亿美元公司的创始人只想专注编程

OpenFeign 的 9 个坑,每个都能让你的系统奔溃相关推荐

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

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

  2. lol祖安服务器维护,听说坑货都去玩LOL无限火力了?这些英雄终于可以拿出来秀啦!...

    原标题:听说坑货都去玩LOL无限火力了?这些英雄终于可以拿出来秀啦! 现在LOL全民流行的时候,也有不少宅女会选择节日开黑,这个时候我们的机会就来了.而正好最近无限火力开了,于是很多小学生都去玩了,那 ...

  3. 跟我学Linux系列1:正确认识和使用一块RAID卡都需要掌握Linux服务器系统配件选型的哪些知识

    1.存储器的层次结构知识 我们从上往下说.操作系统中的存储器构成了一个金字塔,越往上的存储器速度越快,但是价格也越贵,所以也就越小.为了解决高速的处理器和低速的存储器之间的矛盾,上一层的存储器作为下一 ...

  4. 为什么互联网公司都喜欢自研业务系统?

    相信很多人都有困惑,为什么互联网科技公司,都喜欢自研业务系统(例如WMS.CRM.电商系统等),而不是采购市面上成熟的商业软件套件呢? 各类商业软件发展了这么多年,再加上各种SaaS产品,很多业务问题 ...

  5. linux和windows和鸿蒙,linux很好,但为何大家都用Win,鸿蒙系统站错阵营了吗?

    原标题:linux很好,但为何大家都用Win,鸿蒙系统站错阵营了吗? 由目前已知信息可知,华为"鸿蒙系统"很可能基于linux开源程序搭建,这个特点与苹果微软由很大不同.苹果手机目 ...

  6. 计算机配置64位,任何电脑都可以装64位系统吗|是不是所有的电脑都可以装64位系统...

    电脑都可以装64位系统吗?相信大家都看到,现在新买的电脑都是自带64位系统,这时候就有部分用户产生了疑惑,是不是所有电脑都能装64位系统?其实不然!操作系统分32位和64位,就说明了有些电脑不能装64 ...

  7. 现在计算机有64位吗,任何电脑都可以装64位系统吗|是不是所有的电脑都可以装64位系统...

    电脑都可以装64位系统吗?相信大家都看到,现在新买的电脑都是自带64位系统,这时候就有部分用户产生了疑惑,是不是所有电脑都能装64位系统?其实不然!操作系统分32位和64位,就说明了有些电脑不能装64 ...

  8. 黑鲨手机能刷鸿蒙手机系统,一夜之间!所有手机都能用上鸿蒙系统?网友:太强大了!...

    华为是一家非常优秀的国产科技企业,很多人都认为华为不仅是国内科技的领头羊,在国际上也占有非常重要的地位.华为这几年研究的技术在全球来说都算是非常先进的.这跟华为重视科研的程度是有很大的关系的,最近,华 ...

  9. 你需要掌握的有关.NET DateTime类型的知识点和坑位 都在这里

    引言    DateTime数据类型是一个复杂的问题,复杂到足以让你在编写[将日期从Web服务器返回到浏览器]简单代码时感到困惑. ASP.NET MVC 5和 Web API 2/ASP.NETCo ...

最新文章

  1. Windows Caffe中MNIST数据格式转换实现
  2. AI一分钟 | 马斯克:特斯拉内部有人故意搞破坏;亚马逊推出酒店定制版Alexa
  3. c# BindingSource的简单应用
  4. 数据结构实验之链表六:有序链表的建立
  5. AlphaGo、人工智能、深度学习解读以及应用
  6. exchange java对象,【原】Java并发程序的一个应用Exchanger的实例
  7. sublime text3 3176激活
  8. matlab曲线拟合 新浪,Matlab曲线拟合
  9. slf4j使用(二)
  10. UVA11069 A Graph Problem【递推】
  11. 为什么有人不喜欢标准成本
  12. 三人表决器实验报告总结_三人表决器实验报告.doc
  13. java处理Excel数据
  14. Typora下载连接及使用教学
  15. C#基础代码笔记(四)
  16. 【教3妹学java】JVM调优有哪些工具?
  17. ZOJ 3549 Little keng
  18. 仿QQ空间登录,解决键盘挡住输入框的问题
  19. QT线程之 moveToThread() 只能用信号槽方式触发
  20. Polar码的C语言实现之比特反序重排篇

热门文章

  1. libtorch下tensor与img的互相转换
  2. Android Studio如何添加jar包
  3. Kubernetes之StatefulSet
  4. jquery中attr和prop的区别分析
  5. cucumber 使用资料
  6. Java - 利用StringEscapeUtils对字符串进行各种转义与反转义
  7. typhoon-blade c++ lib manager
  8. 单机(CentOS虚拟机)中部署Kubernetes
  9. Pytorch torch.rsqrt()的简单用法
  10. 在windows系统上安装pip的注意事项