最近在使用spring cloud 搭建一个微服务项目,因为需要调用第三方接口,且延迟可能较高,
特意写了个测试接口测试30秒左右延迟能否正常处理,请求中途会在zuul的gate-service 中断于15秒左右,
并抛出如下异常
com.netflix.zuul.exception.ZuulException: Forwarding error
...
...
...
Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: api-service timed-out and no fallback available.
...
...
...
修改了多次配置都未生效,于是就仔细研究了一下cloud中的各种组件的超时配置并整理如下
@Bean
@LoadBalanced
//不管是否有@LoadBalanced注解,都可以使用如下方式设置超时
public RestTemplate restTemplate(){
SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
simpleClientHttpRequestFactory.setConnectTimeout(1000);
simpleClientHttpRequestFactory.setReadTimeout(1000);
return new RestTemplate(simpleClientHttpRequestFactory);
}
#全局设置
ribbon:
ReadTimeout: 40000 #单位ms
ConnectTimeout: 40000 #单位ms
#局部设置
#Ribbon所使用的虚拟主机名,
#一般和Eureka Server上注册的服务名称一致,
#即与spring.application.name一致
:
ribbon:
ReadTimeout: 40000 #单位ms
ConnectTimeout: 40000 #单位ms
1、Edgware之前版本,可实例化一个类型为feign.Request.Options的bean,
参考org.springframework.cloud.netflix.ribbon.FeignRibbonClientAutoConfiguration#feignRequestOptions中的写法
@Bean
Request.Options feignOptions() {
return new Request.Options(/**connectTimeoutMillis**/1000, /** readTimeoutMillis **/1000);
}
//超时时间设置,开启重试机制,默认为5次(包含首次请求)
package com.example.demo;
import feign.Request;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfigure {
public static int connectTimeOutMillis = 12000;//超时时间
public static int readTimeOutMillis = 12000;
@Bean
public Request.Options options() {
return new Request.Options(connectTimeOutMillis, readTimeOutMillis);
}
@Bean
public Retryer feignRetryer() {
return new Retryer.Default();
}
}
2、Spring Cloud Edgware开始,可使用如下配置属性进行设置
feign: client: config:
: #使用@FeignClient注解的对应FeignClient接口名,如果写成default,则表示通用配置 connectTimeout: 30000 # 连接超时设置,单位ms readTimeout: 30000 #读取超时设置,单位ms
一般feignClient都会跟随熔断器Hystrix一起使用,所以就需要同时配置下面Hystrix的超时设置
hystrix: command:
: #Hystrix Command一般情况下与 一致,即实施远程调用的FeignClient名,如设置为default则表示通用设置 execution: timeout: enabled: true #超时开关,默认开启,即true isolation: thread: timeoutInMilliseconds: 30000 #超时时间设置,单位ms
因为Zuul整合了Ribbon以及Hystrix,超时比较复杂,
分为以下两种情况
Zuul路由配置如下
zuul: routes: api-service: #给路由起的別名,可任意起名,一般与
服务同名 path: /gameapi/** #设置 对应的路径,可以将请求地址由/api-service/**换成/gameapi/**来进行调用 serviceId: api-service #指定
此时,Zuul的超时与Ribbon、Hystrix相关,需要使用如下配置设置超时
hystrix: command: default: #hystrix的通用超时配置 execution: isolation: strategy: THREAD thread: timeoutInMilliseconds: 40000 #和ribbon配合使用,必须单独配置指定路由,上面的default超时配置未能生效 api-service: #
可在Hystrix Dashboard 上看到,大部分情况下与 相同 execution: isolation: strategy: THREAD thread: timeoutInMilliseconds: 40000 #全局配置ribbon超时 ribbon: ReadTimeout: 40000 #单位ms ConnectTimeout: 40000 #单位ms #单独配置指定路由的ribbon超时 api-service: ribbon: ReadTimeout: 40000 ConnectTimeout: 40000
代码解析:
此种情况下,Zuul转发所使用的过滤器是 org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter
,
在这个过滤器中,整合了Hystrix以及Ribbon。
Zuul路由配置如下
zuul: routes: api-service: #给路由起的別名,可任意起名 url: http://localhost:9002/ #指定的url path: /gameapi/** #url对应的路径,将/gameapi/**映射到http://localhost:9002/**
需要注意的是,
使用这种方式配置的路由不会作为HystrixCommand执行,
同时也不能使用Ribbon来负载均衡多个URL。
(题外话:如果希望不破坏Zuul的Hystrix、Ribbon特性,可以为Ribbon禁用Eureka )
此时的Zuul的超时只与如下两个配置相关
zuul: host: socket-timeout-millis: 40000 connect-timeout-millis: 40000
代码解析:
直接配置URL路由的方式,用不上Ribbon,也用不上Hystrix,
Zuul转发所使用的过滤器是org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter
,
在这个过滤器中,Zuul使用Apache HttpClient进行转发。
在现实场景中,有时候可能两种路由方式配合使用,因此,建议大家配置以上所有属性。
可参考链接加深理解
Spring Cloud组件那么多超时设置,如何理解和运用?
Zuul超时问题,微服务响应超时,zuul进行熔断
Feign的超时与重试设置(SpringCloud2.0)
Spring Cloud各组件超时总结
github上的议题
Read Timeout on Request #321
Setting up Ribbon's Connection timeout in microservice environment #3323