Feign重试不生效问题的发现,主要还是因为上篇文章《SpringCloud Zuul(Ribbon)重试配置不生效解决办法》里面介绍的原因。当我解决了Zuul重试不生效的问题,测试发现只有如下场景:zuul-->访问A1、A2,A服务返回超时,也就是说Api接口的第一级跨度超过zuul配置ribbon.ReadTimeout的值才会触发ribbon重试。场景一如下图:
场景二如下图,Api接口跨度多个服务的调用:
此时ReadTimeout有两种情况:
1、Zuul网关的ribbon.ReadTimeout>服务端feign.client.config.default.readTimeout。
比如:Zuul网关的ribbon.ReadTimeout=3000,服务端配置的feign.client.config.default.readTimeout=1000,当请求从Zuul网关进来,负载均衡到任意的A服务节点,比如A1,此时A1通过feign调用B服务和C服务的任意节点,比如B2和C1。此时分两种情况:
a.当A1并发请求B2和C1,此时如果有一个接口超时,或者两个接口都超时,那么ReadTime都是1s左右,而并没有达到ribbon.ReadTimeout=3000,所以不会触发网关的ribbon重试,所以此时接口没有返回正常的结果。
b.当A1顺序请求B2和C1,此时如果有一个接口超时,那么ReadTime为1s左右,如果是两个接口都超时,那么ReadTime都是2s左右,而并没有达到ribbon.ReadTimeout=3000,所以不会触发网关的ribbon重试,所以此时接口没有返回正常的结果。
所以只要A服务处理请求的时间没有超过在Zuul配置ribbon.ReadTimeout的值,那么都不会触发ribbon的重试。
2、Zuul网关的ribbon.ReadTimeout=服务端feign.client.config.default.readTimeout。
比如:Zuul网关的ribbon.ReadTimeout=1000,服务端配置的feign.client.config.default.readTimeout=1000,当请求从Zuul网关进来,负载均衡到任意的A服务节点,比如A2,此时A2通过feign调用B服务和C服务的任意节点,比如B1和C2。此时不管是调用B1或者C2超时,或者都超时,那么都会触发Zuul网关的ribbon重试,重试次数主要由ribbon.MaxAutoRetries和ribbon.MaxAutoRetriesNextServer配置的值决定。
比如ribbon.MaxAutoRetries=0,ribbon.MaxAutoRetriesNextServer=1那么,Zuul会根据配置,重新调用A1进行重试,而A1也是通过feign调随机用B服务和C服务的任意节点。
总结以上两种情况,A服务调用调用B服务或者C服务任意节点超时,A服务都不会对B服务和C服务的当前或者其他节点进行重试。
那么怎么样,才能让服务A调用服务B超时的时候,进行重试呢?网上找了些资料,总结如下:
1、Feign组件默认使用Ribbon的重试机制并增加了根据状态码判断重试机制,默认情况下是不启用的。
2、Feign使用的是Spring Retry组件,需要引入依赖才能启用,也就是网关ribbon重试那个组件。
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
3、引入以后没有正确配置ribbon,默认同一节点会重试5次,即使第一次访问就触发了Zuul网关已经返回超时,并且浏览器已经返回超时结果,Feign也会重试5次,如果刚好网关又触发了重试,重试次数配置得也比较大的话,那么就会产生大量多余的请求,会对系统和服务性能造成一定的影响,哪怕没有触发网关的重试,出现一个节点某个服务故障的时候,也会产生多余的性能开销。
4、根据网上找的资料服务端ribbon正确配置如下:
${spring.application.name}: ribbon: MaxAutoRetries: 1 MaxAutoRetriesNextServer: 1 OkToRetryOnAllOperations: false NFLoadBalancerRuleClassName: AvailabilityFilteringRule feign: client: config: default: connectTimeout: 1000 readTimeout: 1000
OkToRetryOnAllOperations建议不要设置为true,即使接口做了幂等,避免后续哪个接口忘记做幂等产生脏数据。
通过实际的测试,发现接入依赖以后,Feign的请求超时的确会触发重试,但是实际上网关的ribbon.ReadTimeout、ribbon.MaxAutoRetries、ribbon.MaxAutoRetriesNextServer这些参数都会影响Feign的重试可能性和结果,下篇文章《SpringCloud Ribbon和Feign重试参数性能实测对比》详细介绍实际测试结果。