序
ribbon的超时设置,只能按转发的serviceId来分的,无法像nginx那样直接在每个转发的链接里头设置超时时间。这里hack一下,实现url基本的ribbon超时时间设置。具体的思路就是重写RibbonApacheHttpRequest的toRequest方法,然后进行设置。
CustomRibbonApacheHttpRequest
public class CustomRibbonApacheHttpRequest extends RibbonApacheHttpRequest { public CustomRibbonApacheHttpRequest(RibbonCommandContext context) { super(context); } @Override public HttpUriRequest toRequest(RequestConfig requestConfig) { final RequestBuilder builder = RequestBuilder.create(this.context.getMethod()); builder.setUri(this.uri); for (final String name : this.context.getHeaders().keySet()) { final List<String> values = this.context.getHeaders().get(name); for (final String value : values) { builder.addHeader(name, value); } } for (final String name : this.context.getParams().keySet()) { final List<String> values = this.context.getParams().get(name); for (final String value : values) { builder.addParameter(name, value); } } if (this.context.getRequestEntity() != null) { final BasicHttpEntity entity; entity = new BasicHttpEntity(); entity.setContent(this.context.getRequestEntity()); // if the entity contentLength isn't set, transfer-encoding will be set // to chunked in org.apache.http.protocol.RequestContent. See gh-1042 if (this.context.getContentLength() != null) { entity.setContentLength(this.context.getContentLength()); } else if ("GET".equals(this.context.getMethod())) { entity.setContentLength(0); } builder.setEntity(entity); } customize(this.context.getRequestCustomizers(), builder); //todo 这里处理个性的timeout信息 if(uri.getPath().equals("/review/timeout")){ RequestConfig.Builder configBuilder = RequestConfig.copy(builder.getConfig()); configBuilder.setConnectionRequestTimeout(30*1000); configBuilder.setConnectTimeout(30*1000); configBuilder.setSocketTimeout(30*1000); builder.setConfig(configBuilder.build()); }else{ builder.setConfig(requestConfig); } return builder.build(); } }
CustomHttpClientRibbonCommand
public class CustomHttpClientRibbonCommand extends HttpClientRibbonCommand { public CustomHttpClientRibbonCommand(String commandKey, RibbonLoadBalancingHttpClient client, RibbonCommandContext context,
ZuulProperties zuulProperties) { super(commandKey, client, context, zuulProperties); } public CustomHttpClientRibbonCommand(String commandKey, RibbonLoadBalancingHttpClient client, RibbonCommandContext context,
ZuulProperties zuulProperties,
ZuulFallbackProvider zuulFallbackProvider) { super(commandKey, client, context, zuulProperties, zuulFallbackProvider); } @Override protected RibbonApacheHttpRequest createRequest() throws Exception { RibbonApacheHttpRequest ribbonApacheHttpRequest = new CustomRibbonApacheHttpRequest(this.context); return ribbonApacheHttpRequest; } }
CustomHttpClientRibbonCommandFactory
public CustomHttpClientRibbonCommandFactory(SpringClientFactory clientFactory, ZuulProperties zuulProperties) { super(clientFactory, zuulProperties); this.clientFactory = clientFactory; this.zuulProperties = zuulProperties; } public CustomHttpClientRibbonCommandFactory(SpringClientFactory clientFactory, ZuulProperties zuulProperties,
Set<ZuulFallbackProvider> fallbackProviders) { super(clientFactory, zuulProperties, fallbackProviders); this.clientFactory = clientFactory; this.zuulProperties = zuulProperties; } @Override public HttpClientRibbonCommand create(RibbonCommandContext context) { ZuulFallbackProvider zuulFallbackProvider = getFallbackProvider(context.getServiceId()); final String serviceId = context.getServiceId(); final RibbonLoadBalancingHttpClient client = this.clientFactory.getClient( serviceId, RibbonLoadBalancingHttpClient.class); client.setLoadBalancer(this.clientFactory.getLoadBalancer(serviceId)); return new CustomHttpClientRibbonCommand(serviceId, client, context, zuulProperties, zuulFallbackProvider); } }
配置
@Autowired(required = false) private Set<ZuulFallbackProvider> zuulFallbackProviders = Collections.emptySet(); @Bean @ConditionalOnMissingBean public RibbonCommandFactory<?> ribbonCommandFactory( SpringClientFactory clientFactory, ZuulProperties zuulProperties) { return new CustomHttpClientRibbonCommandFactory(clientFactory, zuulProperties, zuulFallbackProviders); }
网关的超时层级
zuul
zuul: max: host: connections: 500 host: socket-timeout-millis: 60000 connect-timeout-millis: 60000
ribbon
ribbon: ReadTimeout: 10000 ConnectTimeout: 10000 MaxAutoRetries: 0 MaxAutoRetriesNextServer: 1 eureka: enabled: true
hystrix
hystrix: command: default: execution: timeout: enabled: true isolation: thread: timeoutInMilliseconds: 60000
小结
走网关的话,有三层的超时时间,一个是zuul的,一个是ribbon的,还有一个是hystrix的。hystrix的超时设置,AbstractRibbonCommand这个类没有暴露设置hystrix的Setter方法出来,所以无法通过继承的方式来扩展。因此要自定义ribbon超时的话,需要这个超时时间是小于hystrix的,不然就提前被hystrix超时了,无法起到效果。