Ribbon超时及重试配置

 

配置实例

##timeout config
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 60000
ribbon:
  ReadTimeout: 60000
  ConnectTimeout: 60000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1
  eureka:
    enabled: false

zuul:
  max:
    host:
      connections: 500
  host:
    socket-timeout-millis: 60000
    connect-timeout-millis: 60000

MaxAutoRetries

Max number of retries on the same server (excluding the first try)

MaxAutoRetriesNextServer

Max number of next servers to retry (excluding the first server)

docs
ribbon-Getting-Started

https://segmentfault.com/a/1190000007290888

聊聊ribbon的超时时间设置

本文主要研究一下ribbon的超时时间设置

配置

实例

ribbon:
  ReadTimeout: 10000
  ConnectTimeout: 10000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1
  eureka:
    enabled: true

RibbonClientConfiguration

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonClientConfiguration.java

@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties //Order is important here, last should be the default, first should be optional // see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653 @Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class}) public class RibbonClientConfiguration { public static final int DEFAULT_CONNECT_TIMEOUT = 1000; public static final int DEFAULT_READ_TIMEOUT = 1000; @RibbonClientName private String name = "client"; // TODO: maybe re-instate autowired load balancers: identified by name they could be // associated with ribbon clients @Autowired private PropertiesFactory propertiesFactory; @Bean @ConditionalOnMissingBean public IClientConfig ribbonClientConfig() { DefaultClientConfigImpl config = new DefaultClientConfigImpl(); config.loadProperties(this.name); config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT); config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT); return config; } //...... } 
  • 这里设置默认的超时值,都是1000毫秒,设置在DefaultClientConfigImpl

AbstractLoadBalancingClient

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/support/AbstractLoadBalancingClient.java

public abstract class AbstractLoadBalancingClient<S extends ContextAwareRequest, T extends IResponse, D> extends AbstractLoadBalancerAwareClient<S, T> implements ServiceInstanceChooser { protected int connectTimeout; protected int readTimeout; //...... @Override public void initWithNiwsConfig(IClientConfig clientConfig) { super.initWithNiwsConfig(clientConfig); RibbonProperties ribbon = RibbonProperties.from(clientConfig); this.connectTimeout = ribbon.connectTimeout(DEFAULT_CONNECT_TIMEOUT); this.readTimeout = ribbon.readTimeout(DEFAULT_READ_TIMEOUT); this.secure = ribbon.isSecure(); this.followRedirects = ribbon.isFollowRedirects(); this.okToRetryOnAllOperations = ribbon.isOkToRetryOnAllOperations(); } //...... } 
  • 这里从RibbonProperties读取超时参数,然后放到类成员变量connectTimeout及readTimeout
  • RibbonProperties就最后是从IClientConfig读取

RibbonLoadBalancingHttpClient

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClient.java

// TODO: rename (ie new class that extends this in Dalston) to ApacheHttpLoadBalancingClient
public class RibbonLoadBalancingHttpClient extends AbstractLoadBalancingClient<RibbonApacheHttpRequest, RibbonApacheHttpResponse, CloseableHttpClient> { //...... @Override public RibbonApacheHttpResponse execute(RibbonApacheHttpRequest request, final IClientConfig configOverride) throws Exception { IClientConfig config = configOverride != null ? configOverride : this.config; RibbonProperties ribbon = RibbonProperties.from(config); RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(ribbon.connectTimeout(this.connectTimeout)) .setSocketTimeout(ribbon.readTimeout(this.readTimeout)) .setRedirectsEnabled(ribbon.isFollowRedirects(this.followRedirects)) .build(); request = getSecureRequest(request, configOverride); final HttpUriRequest httpUriRequest = request.toRequest(requestConfig); final HttpResponse httpResponse = this.delegate.execute(httpUriRequest); return new RibbonApacheHttpResponse(httpResponse, httpUriRequest.getURI()); } //...... } 
  • 这里execute方法从IClientConfig构造RequestConfig,会设置connectTimeout及socketTimeout
  • 如果configOverride为null,则使用抽象类的默认配置

OkHttpLoadBalancingClient

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/okhttp/OkHttpLoadBalancingClient.java

public class OkHttpLoadBalancingClient extends AbstractLoadBalancingClient<OkHttpRibbonRequest, OkHttpRibbonResponse, OkHttpClient> { //...... @Override public OkHttpRibbonResponse execute(OkHttpRibbonRequest ribbonRequest, final IClientConfig configOverride) throws Exception { boolean secure = isSecure(configOverride); if (secure) { final URI secureUri = UriComponentsBuilder.fromUri(ribbonRequest.getUri()) .scheme("https").build().toUri(); ribbonRequest = ribbonRequest.withNewUri(secureUri); } OkHttpClient httpClient = getOkHttpClient(configOverride, secure); final Request request = ribbonRequest.toRequest(); Response response = httpClient.newCall(request).execute(); return new OkHttpRibbonResponse(response, ribbonRequest.getUri()); } OkHttpClient getOkHttpClient(IClientConfig configOverride, boolean secure) { IClientConfig config = configOverride != null ? configOverride : this.config; RibbonProperties ribbon = RibbonProperties.from(config); OkHttpClient.Builder builder = this.delegate.newBuilder() .connectTimeout(ribbon.connectTimeout(this.connectTimeout), TimeUnit.MILLISECONDS) .readTimeout(ribbon.readTimeout(this.readTimeout), TimeUnit.MILLISECONDS) .followRedirects(ribbon.isFollowRedirects(this.followRedirects)); if (secure) { builder.followSslRedirects(ribbon.isFollowRedirects(this.followRedirects)); } return builder.build(); } //...... } 
  • 这里是通过configOverride或默认的config来构建指定超时参数的OkHttpClient
  • 相比较于apache httpclient通过request config来设置超时时间,OkHttpClient是通过client来设置的,这样可能存在一个问题,就是OkHttpClient没法用单例,每次都得new一个

clientConfig传递

RibbonHttpRequest

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonHttpRequest.java

public class RibbonHttpRequest extends AbstractClientHttpRequest { //...... @Override protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { try { addHeaders(headers); if (outputStream != null) { outputStream.close(); builder.entity(outputStream.toByteArray()); } HttpRequest request = builder.build(); HttpResponse response = client.executeWithLoadBalancer(request, config); return new RibbonHttpResponse(response); } catch (Exception e) { throw new IOException(e); } } //...... } 
  • 这里client.executeWithLoadBalancer(request, config)使用的是RibbonHttpRequest的config配置

RibbonClientHttpRequestFactory

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonClientHttpRequestFactory.java

public class RibbonClientHttpRequestFactory implements ClientHttpRequestFactory { private final SpringClientFactory clientFactory; public RibbonClientHttpRequestFactory(SpringClientFactory clientFactory) { this.clientFactory = clientFactory; } @Override @SuppressWarnings("deprecation") public ClientHttpRequest createRequest(URI originalUri, HttpMethod httpMethod) throws IOException { String serviceId = originalUri.getHost(); if (serviceId == null) { throw new IOException( "Invalid hostname in the URI [" + originalUri.toASCIIString() + "]"); } IClientConfig clientConfig = this.clientFactory.getClientConfig(serviceId); RestClient client = this.clientFactory.getClient(serviceId, RestClient.class); HttpRequest.Verb verb = HttpRequest.Verb.valueOf(httpMethod.name()); return new RibbonHttpRequest(originalUri, verb, client, clientConfig); } } 
  • ClientHttpRequest是通过RibbonClientHttpRequestFactory这个工厂创建的
  • clientConfig是RibbonClientHttpRequestFactory这个工厂根据serviceId获取的,默认是DefaultClientConfigImpl,从配置文件读取,serviceId自己的个性化配置参数会覆盖默认值,读取不到的就是默认的参数。

小结

spring cloud netflix的ribbon,其超时时间配置有ReadTimeout以及ConnectTimeout,分别是设置的socketTimeout以及connectTimeout,创建请求的时候,会读取指定配置,没有的话,就取默认的配置,设置超时时间。

doc



作者:go4it
链接:https://www.jianshu.com/p/eb63697adca8
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 

Spring cloud 微服务架构之Ribbon/Fegin连接超时ReadTimeout问题

问题描述:

近期用Spring cloud 开发微服务架构时候,在服务与服务之间调用调试代码时候,出现链接超时。

错误信息:

Read timed out executing GET http://service-batch/batchmanagement/datatransfer/querybyplanid?planid=PL00000102。

发生原因:

用IDE开发Debug模式调试代码时候,在处理该服务与其他服务调用时候,由于debug模式调试代码花费一些时间,结果出现Fegin 连接超时问题。

解决办法:

在application.properice属性文件中添加

#Fegin 连接超时

ribbon.ReadTimeout=60000
ribbon.ConnectTimeout=60000
ribbon.MaxAutoRetries=0
ribbon.MaxAutoRetriesNextServer=1 

技术讲解:

微服务间调用其实走的是http请求,debug了一下默认的ReadTimeout时间为5s,ConnectTimeout时间为2s,

我使用的是Fegin进行微服务间调用,底层用的还是Ribbon。
---------------------
作者:喜欢健身的程序员
来源:CSDN
原文:https://blog.csdn.net/m0_38016299/article/details/78391461
版权声明:本文为博主原创文章,转载请附上博文链接!

 

springcloud2.x 设置feign、ribbon和hystrix的超时问题(配置文件)

#ribbon的超时时间   (一般情况下 都是 ribbon 的超时时间(<)hystrix的超时时间(因为涉及到ribbon的重试机制) )
ribbon:
  ReadTimeout: 6000
  ConnectTimeout: 6000
  MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用
  MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用
  OkToRetryOnAllOperations: false  #是否所有操作都重试 

#hystrix的超时时间  (一般情况下 都是 ribbon 的超时时间(<)hystrix的超时时间(因为涉及到ribbon的重试机制) )
#这种写法是把默认的超时时间改成8秒,而把另外一个自定义的 Feign 客户端中的某方法超时时间定成10秒(格式是类名#方法名()
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
      isolation:
        thread:
          timeoutInMilliseconds: 8000
    "***FeignClient#***method()": #格式是   类名#方法名()
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 10000    
---------------------
作者:执意丨
来源:CSDN
原文:https://blog.csdn.net/ab52262879/article/details/84100596
版权声明:本文为博主原创文章,转载请附上博文链接!

 

Zuul、Ribbon、Feign、Hystrix使用时的超时时间(timeout)设置问题

写在前面
因为测试 Feign + Hystrix 搭配模式下的降级(fallback)超时时间自定义问题,算是踩了个坑,然后就顺便查+测试了下 Zuul、Ribbon + Hystrix 模式下分别怎么设置

测试这些东西费了不少力气,因为这几个模块要么搭配使用、要么有内部依赖别的模块、要么对其他模块做了封装,这个配置项就变得千奇百怪,而且网上的东西,一直觉得有个很"严重"的问题,就是版本不明,版本号都不一样,解决方案或者说配置方式可能完全不同,而很多的文章中也没有提及他们用的是哪个版本,搞得我是晕头转向(毕竟我不是这些服务模块的开发者或者长期的使用者,不是非常了解这些东西的版本演进过程)

所以这里是查了不少的资料,测试通过了一些方案,也算是自己总结记录一下

注意!

这里都是基于有 Eureka 做服务中心为前提的

工具
Eclipse Oxygen

Spring Boot 2.0.5.RELEASE

Spring Cloud Finchley.SR1

Eureka 1.9.3

Zuul 1.3.1

Ribbon 2.2.5

Feign 9.5.1

Hystrix 1.5.12

Feign + Hystrix
这个栗子的源码看这里

0. 默认基本配置
最基本的配置,是 Hystrix 自己的一长串配置:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds,但在 Feign 模块中,单独设置这个超时时间不行,还要额外设置 Ribbon 的超时时间,比如:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000

ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000

 

关于 Hystrix 的配置,这里有官方的说明:


可以看到实例配置中,替代 default 的,是 HystrixCommandKey,这个值在下面会说到

1. 不同实例分别配置
如果更进一步,想把超时时间细分到不同的 service 实例上也可以实现,比如:

 

@FeignClient(
    value = "hello-service",
    fallback = MyFeignClientHystric.class)
public interface MyFeignClient {
    @RequestMapping("/hello")
    String sayHelloByFeign();

    @RequestMapping("/why")
    String sayWhyByFeign();
}

 

 

 

hystrix:
  command:
    "MyFeignClient#sayWhyByFeign()":
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 9000
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000

ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000

 

这种写法是把默认的超时时间改成2秒,而把另外一个自定义的 Feign 客户端中的某方法超时时间定成9秒(格式是类名#方法名(),如果方法有入参,也要把入参的类型拼上),这里的 MyFeignClient#sayWhyByFeign() 就代表了上面说到的 commandKey,而这种写法,则是 Feign 模块中特殊的:

ryanjbaxter commented on 26 Jul

If you had a Feign client called MyClient and it had a method called search that took in a single String parameter than you would use the following property
hystrix.command.MyClient#search(String).execution.isolation.thread.timeoutInMilliseconds

看 issue 里 Spring Cloud 的官方人员的说法,这种格式是他们进行的封装,所以我们要设置,就只能这么写

Ribbon + Hystrix
这个栗子的源码看这里

0. 默认基本配置
在使用 Ribbon 时,只需要配置 Hystrix 的超时时间就可以生效,不需要额外配置 Ribbon 的超时时间,比如:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 9000

 


1. 不同实例分别配置
想细分服务超时时间时:

如果是同一个服务实例下的不同接口,想使用不同的超时时间,可以把 @HystrixCommand 中的 commandKey 定义成不同的值,然后在 yml 中分别设置

@HystrixCommand(
    commandKey = "helloService-sayHello",
    fallbackMethod = "sayHelloDefault")
public String sayHelloByRibbon() {
    return restTemplate.getForObject("http://HELLO-SERVICE/hello", String.class);
}

public String sayHelloDefault() {
    return "hello service error, this is default say hello method";
}

@HystrixCommand(
    commandKey = "helloService-sayWhy",
    fallbackMethod = "sayWhyDefault")
public String sayWhyByRibbon() {
    return restTemplate.getForObject("http://HELLO-SERVICE/why", String.class);
}

public String sayWhyDefault() {
    return "hello service error, this is default say why method";
}

 

 

 

hystrix:
  command:
    helloService-sayWhy:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1500

 


如果想统一设置同一个服务实例中各方法的超时时间,经测试,可以把不同方法上的 commandKey 设置成相同的值,这样在 yml 中对该 key 做超时配置就能同时生效了:

 

@HystrixCommand(
    commandKey = "helloService",
    fallbackMethod = "sayHelloDefault")
public String sayHelloByRibbon() {
    return restTemplate.getForObject("http://HELLO-SERVICE/hello", String.class);
}

public String sayHelloDefault() {
    return "hello service error, this is default say hello method";
}

@HystrixCommand(
    commandKey = "helloService",
    fallbackMethod = "sayWhyDefault")
public String sayWhyByRibbon() {
    return restTemplate.getForObject("http://HELLO-SERVICE/why", String.class);
}

public String sayWhyDefault() {
    return "hello service error, this is default say why method";
}

 

 

hystrix:
  command:
    helloService:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000

 

Zuul
这个栗子的源码看这里,Zuul 中的降级是用了 FallbackProvider,简单的使用可以看我源码中的 HelloFallbackProvider.java 和 HiFallbackProvider.java,我也是参考了官方的文档说明和例子

0. 默认基本配置
zuul 中配置超时时间,据官方的介绍,分两种情况:

用 serviceId 进行路由时,使用 ribbon.ReadTimeout 和 ribbon.SocketTimeout 设置

用指定 url 进行路由时,使用 zuul.host.connect-timeout-millis 和 zuul.host.socket-timeout-millis 设置

因为我的代码中是用 serviceId 的方式,所以参考了第一种配置,比如:

zuul:
  routes:
    helloService:
      path: /hello-service/**
      serviceId: hello-service
    hiService:
      path: /hi-service/**
      serviceId: hi-service

ribbon:
  ConnectTimeout: 5000
  ReadTimeout: 5000

 

 

1. 不同实例分别配置
Ribbon 的配置项还可以加一个 ClientName 为前缀(这个方法的出处在官方的 wiki),区分不同客户端下的配置,这个 ClientName 我是直接用了 serviceId,测试了正常,但还可以用或者说应该用什么值,这个我还没有找到官方的说明。。

zuul:
  routes:
    helloService:
      path: /hello-service/**
      serviceId: hello-service
    hiService:
      path: /hi-service/**
      serviceId: hi-service

hello-service:
  ribbon:
    ConnectTimeout: 5000
    ReadTimeout: 5000

hi-service:
  ribbon:
    ConnectTimeout: 500
    ReadTimeout: 500

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

 


另外还做了测试,如果同时配置了 Ribbon 和 Hystrix 的超时时间,则以最小的为准,比如上述的配置中,如果 hi-service 的接口调用超过了 0.5 秒,则就会触发超时

总结
目前的学习和测试结果来看:

单纯的 Ribbon + Hystrix 搭配使用时,配置是最灵活的,两者没有相互干涉,可以自由定义 commandKey 来实现超时时间的配置

Feign + Hystrix 搭配时,由于 Feign 封装了 Hystrix 所需的 commandKey,我们不能自定义,所以同一个 FeignClient 下的服务接口不能方便的统一配置,如果有相应的业务需求,或许只能对每个特殊的接口方法做独立的超时配置(找到新方法的话再回来更新)

Zuul + Hystrix 搭配时,和上述的情况相反,能对不同服务实例做不同的超时配置,但不能再细化到服务下的具体接口方法
---------------------
作者:PriestM
来源:CSDN
原文:https://blog.csdn.net/mxmxz/article/details/84633098
版权声明:本文为博主原创文章,转载请附上博文链接!

 

转载于:https://www.cnblogs.com/softidea/p/10563972.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值