Spring Cloud Feign的超时和重试

Feign

Feign在英语中是伪装的意思,这里Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。

这样我们就不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。

Feign也是Netflix开发的,是一种声明式、模板化的HTTP客户端,Feign可以让我们更加便捷地调用HTTP API。

Feign支持自带注解或JAX-RS注解。SpringCloud对Feign进行了增强,使Feign支持SpringMVC注解,并整合了Ribbon和Hystrix。

超时

在微服务架构中,一个服务对服务的访问至少得配置一个超时时间,不可能请求一个接口等了好几分钟都还没有返回,在设置超时时间后,超时后就认为这次接口请求失败了。

重试

服务B调用服务A,服务A部署了3台机器,现在服务B通过负载均衡的算法,调用到了服务A的机器1,因为服务A的机器1宕机了,请求超时了,可以让服务B再次请求一次服务A的机器1,如果还是不行,再请求服务A的机器2,如果还是不行,就再请求服务A的服务3,这就是重试机制。

Spring Cloud Feign 的重试机制的演进

在早期的Feign也有重试的模块,但是后来发现和Ribbon冲突了,于是SpringCloud团队在后面的版本将Feign的重试设置为NERVER_RETRY了。因此,对于Camden以及以后的版本,Feign的重试可使用如下属性进行配置:

注意,feign的超时时间优先级更高。

超时和重试源码

超时

如果feign没有配置超时时间,则读取ribbon的配置,否则读取feign的超时配置

FeignLoadBalancer.execute(),发送实际的http请求的时候,就会传入设置的超时参数

重试

Feign的重试

Feign本身也具备重试能力,在早期的Spring Cloud中,Feign使用的是 feign.Retryer.Default#Default() ,重试5次。但Feign整合了Ribbon,Ribbon也有重试的能力,此时,就可能会导致行为的混乱。

Spring Cloud意识到了此问题,因此做了改进,将Feign的重试改为 feign.Retryer#NEVER_RETRY ,如需使用Feign的重试,只需使用Ribbon的重试配置即可。

SynchronousMethodHandler.invoke()方法里面,如果抛了异常的话,也会默认根据Retryer进行重试。

Ribbon的重试

因为SpringCloud的Feign重试默认是NEVER_RETRY,所以主要是靠Ribbon的重试机制。

FeignLoadBalancer.getRequestSpecificRetryHandler()方法中,会读取配置的几个参数:OkToRetryOnAllOperations、MaxAutoRetries、MaxAutoRetriesNextServer

LoadBalancerCommand.submit()方法中,读取RetryHandler中配置的参数,会根据请求的情况,是否报错,是否报异常,进行重试的控制

LoadBalancerCommand包含了大量的重试逻辑,这里是判断是否对同一台机器进行重试

重试都会进入retryPolicy方法,判断是否需要进行重试,然后利用rxjava的retry方法进行重试。

对其他机器进行重试

上面的逻辑是服务宕机的时候的重试逻辑,在超时的时候重试逻辑却是在RetryableFeignLoadBalancer里

0

Spring Cloud Feign 如何配置负载均衡策略?

Spring Cloud Feign 如何配置负载均衡策略?

代码示例

1.使用@FeignClient注解发现服务

服务提供者的controller

client消费者端

在使用@FeignClient注解的时候,默认使用了ribbon进行客户端的负载均衡,默认策略随机,若要更改策略,需修改消费者yml中的配置,如下:

可以看到ribbon的策略主要有以下几种:

  1. com.netflix.loadbalancer.RandomRule #配置规则 随机,几个提供者间随机访问
  2. com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询,轮流访问
  3. com.netflix.loadbalancer.RetryRule #配置规则 重试,在一段时间内通过RoundRobinRule选择服务实例,一段时间内没有选择出服务则线程终止
  4. com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重,根据平均响应时间来计算权重
  5. com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略

总结

Spring Cloud Feign 如何配置负载均衡策略到这边就介绍完了,大家需要结合自己实际业务场景,来选择合适的负载均衡策略。

0

Spring Cloud Feign 如何自定义编码器、解码器和客户端?

Spring Cloud Feign 为何需要自定义编码器、解码器?

已有的编解码器无法满足需求。

说明

由Feign的实现原理可知,编码器(Encoder)是用来将RequestBean转换成 Http报文正文,解码器(Decoder)是用来将http server的返回报文转换成Response Bean。

spring cloud feign encoder decoder 图解
spring cloud feign encoder decoder 图解

Spring Cloud Feign 的编码器、解码器和客户端都是支持自定义扩展,可以对请求以及结果和发起请求的过程进行自定义实现,Feign 默认encoder实现是SpringEncoder,默认decocer实现是ResponseEntityDecoder,另外还有一些其它的编解码器。

Encoder/ Decoder 实现 说明
JacksonEncoder,JacksonDecoder 基于 Jackson 格式的持久化转换协议
GsonEncoder,GsonDecoder 基于Google GSON 格式的持久化转换协议
SaxEncoder,SaxDecoder 基于XML 格式的Sax 库持久化转换协议
JAXBEncoder,JAXBDecoder 基于XML 格式的JAXB 库持久化转换协议
ResponseEntityEncoder,ResponseEntityDecoder Spring MVC 基于 ResponseEntity< T > 返回格式的转换协议
SpringEncoder,SpringDecoder 基于Spring MVC HttpMessageConverters 一套机制实现的转换协议 ,应用于Spring Cloud 体系中

所以如果希望支持其他的或者自定义格式就需要编写自己的编码器和解码器。若要实现自己的编码器,需要实现 feign.codec.Encoder 接口,解码器需要实现 feign.codec.Decoder 接口,示例如下:

Spring Cloud Feign 为何需要自定义客户端实现?

默认实现性能差,需要优化。

说明

Feign 默认底层通过JDK 的 java.net.HttpURLConnection 实现了feign.Client接口类,在每次发送请求的时候,都会创建新的HttpURLConnection 链接,这也就是为什么默认情况下Feign的性能很差的原因。可以通过拓展该接口,使用Apache HttpClient 或者OkHttp3等基于连接池的高性能Http客户端。

具体实现请参考这篇文章《Spring Cloud Feign 使用OkHttp或HttpClient覆盖默认客户端》。

总结

实际开发中,每个公司都有一些自己的实现,这些东西搭框架时都已经写好了,自己若只是写写业务代码,是涉及不到这块的。

 

+1

Spring Cloud Feign 使用OkHttp或HttpClient覆盖默认客户端

前言

我们知道,流行的开源Http库的性能均远高于JDK源生的HttpURLConnection,因此实际生产中肯定是用的三方库来发送Http请求。

Feign它提供了feign.Client抽象来发送Http请求,因此使得它拥有良好的扩展性,而恰好Feign的子模块里亦提供了对OkHttp以及Apache HttpClient的整合,本文将教你如何把Feign切换为第三方HC以提高性能。

Feign的模块中有三个关于HC的子模块:feign-okhttp、feign-httpclient、feign-googlehttpclient。

这边以OkHttp为例。

GAV如下

“携带”的okhttp版本号是:3.6.0。(若把Feign调整到最新版本10.7.4,那么它携带的okhttp版本号也就是最新的3.14.6的了)

说明:okhttp虽然目前最新版本是4.x版本的,关于区别你可以简单粗暴的理解:前者是用kotlin改写了,后者还是用Java写的,其它的并无什么变化。
所以,在Server端使用okhttp,请务必使用3.x版本~移动端可酌情使用4.x版本

我们知道Feign最终是通过它的feign.Client这个API去发送远程请求的,而feign.Client是可以在构建的时候由使用者自定义指定的。有了以上理论的支撑,若想切换最终发送Http请求的HC,仅需在构建时使用自己的feign.Client即可。

使用示例

构建Feign时,指定使用OkHttpClient:

当然,如果你已经有现成的定制好的okhttpClient里,直接使用即可,形如这样:

源码解析

feign-okhttp这个jar包内,有且仅有一个类:feign.okhttp.OkHttpClient,它是对feign.Client接口的实现。

这个逻辑不难,其实就一普通的Http请求的发送,不同之处在于进行了两次数据转换:

  • Request之前的转换
  • Response之间的转换

其中,需要特别特别注意的是:请务必确保每次请求都是线程安全的。feign.Client接口的Javadoc也特别强调了这一点~

总结

Apache HttpClient 和 GoogleHttpClient 的实现也是一样,这边就不详述了。

0

springcloud feign 设置 header 方法总结

很多时候,我们在微服务间调用时需要在 request header 里添加 token 信息,那么 springcloud open feign 如何设置 header 呢?

方法一:实现RequestInterceptor接口

方法二:在@RequestMapping注解里添加headers属性

0

zuul + feign + redis + oauth 实现统一认证

本文是接着《使用oltu实现自己的oauth2.0认证服务(一)》和《使用oltu实现自己的oauth2.0认证服务(二)》这两篇之后写的,主体框架是spring cloud搭建。

oauth resource 服务

zuul网关服务

添加一个feign client

OauthServiceFallback统一未认证处理类

实现ZuulFilter接口

0

FeigninClient里如何进行重试(Retry)和超时(timeout)配置

从源代码里了解默认值

默认最大尝试次数

重试逻辑

可以看到,attampt的初始值为1,即第一个请求被累加。 首先,执行try> = maxAttempts判断,然后执行该尝试。 也就是说,将maxAttempts设置为2意味着重试一次。

默认超时时间

参数配置

配置超时

配置重试

返回时间

默认重试返回时间(1s connectTimeout,1s readTimeout)

在一定时间内服务的请求百分比(ms)

没有重试(1s connectTimeout,1s readTimeout)

在一定时间内服务的请求百分比(毫秒)

没有重试(5s connectTimeout,5s readTimeout)

在一定时间内服务的请求百分比(毫秒)

总结

FeigninClient的默认connectTimeout为10s,readTimeout为60。仅设置超时可能不会立即生效,因为默认重试次数为5次。 因此,如果想要快速失败,则必须同时自定义超时和重试的参数,并应确保反向代理。 例如,nginx的proxy_connect_timeout和proxy_read_timeout必须大于feign的配置才能生效。 否则,nginx的504网关超时仍然会被外部用户感知,并且无法实现回滚效果。

0