Ribbon、Feign、Hystrix和Zuul超时重试设置(一)

刚学Spring Cloud时,被里面的各种组件的超时搞得晕头转向的,所以趁着这段不忙的时间,查找了不少的资料,测试了一些代码,好好总结一下,避免以后忘记掉。

这里Spring Cloud的版本为Greenwich.SR1,代码都是最简单的写法,主要是为了验证各种超时配置。

Ribbon

刚学Spring Cloud,我是通过网上的各种博客教程学习,跟着示例敲代码,下面就是一个ribbon的示例代码:
eureka-client服务:

@RequestMapping("/test")
public String test() {
    int sleepTime = new Random().nextInt(4000);
    System.out.println("sleepTime: " + sleepTime);
    try {
        Thread.sleep(sleepTime); //模拟网络延迟
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "test";
}

eureka-client就是一个简单的服务,提供一个test的接口供ribbon远程调用。
service-ribbon服务:
启动类:

@SpringBootApplication
public class RibbonApplication {

    public static void main(String[] args) {
        SpringApplication.run(RibbonApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

controller:

@RestController
public class TestController {
	
	private final TestService testService;

	@Autowired
	public TestController(TestService testService) {
		this.testService = testService;
	}

	@GetMapping("/test")
	public String test() {
	    return testService.test();
	}
}

service:

@Service
public class TestService {

	public final RestTemplate restTemplate;

	@Autowired
	public TestService(RestTemplate restTemplate) {
		this.restTemplate = restTemplate;
	}

	public String test() {
		return restTemplate.getForObject("http://eureka-client/test", String.class);
	}
}

代码很简单,也没其他的配置,当然一些基本的配置比如注册到eureka server等配置还有依赖我这里就不列出来了。
跑一下:

在这里插入图片描述
可以看到正常返回信息了,但我发现模拟的网络延迟3秒多了还是能正常返回,好奇之下我试了下10秒延迟:

在这里插入图片描述
什么情况,10秒都能正常返回,难道默认没有超时吗?带着这个疑虑,我在service-ribbon服务的yml配置文件中给ribbon设置了一个超时:

ribbon:
    ReadTimeout: 2000
    ConnectionTimeout: 2000

重试了一下发现10秒还是能正常返回,不会超时,嗯?怎么回事?上网搜ribbon超时发现都是这样配置的,难道是新版本改了?我看了下文档好像也不是这么一回事(虽然英语不好)。我又重新上网查找资料,最后发现RestTemplate使用默认构造函数时是使用SimpleClientHttpRequestFactory来创建http请求的,通过debug也可知:

在这里插入图片描述
而查看SimpleClientHttpRequestFactory源码可知SimpleClientHttpRequestFactory默认是没有超时的:

public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {

	private static final int DEFAULT_CHUNK_SIZE = 4096;


	@Nullable
	private Proxy proxy;

	private boolean bufferRequestBody = true;

	private int chunkSize = DEFAULT_CHUNK_SIZE;

	private int connectTimeout = -1;

	private int readTimeout = -1;

	private boolean outputStreaming = true;

	@Nullable
	private AsyncListenableTaskExecutor taskExecutor;
	...
}

这也解释了为什么上面延迟10秒都不会超时。而要想设置超时,就需要对SimpleClientHttpRequestFactory实例设置超时时间并注入到RestTemplate中:

@SpringBootApplication
public class RibbonApplication {

    public static void main(String[] args) {
        SpringApplication.run(RibbonApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(2000);
        requestFactory.setReadTimeout(2000);
        return new RestTemplate(requestFactory);
    }
}

此时,如果超时,就会报错:

在这里插入图片描述
如果想使ribbon.ConnectTimeout ,ribbon.ReadTimeout这两个参数配置生效,则需要多一个配置:

ribbon:
  ReadTimeout: 2000
  ConnectionTimeout: 2000
  http:
    client:
      enabled: true

把ribbon.http.client.enabled设置为true,就会使用RibbonClientHttpRequestFactory,此时ribbon.ConnectTimeout ,ribbon.ReadTimeout 这两个参数配置才会生效

在这里插入图片描述
而如果不配超时时间,默认超时时间是1秒,超时后默认会重试一次。

在这里插入图片描述
可以通过以下配置来设置重试次数:

ribbon:
  ReadTimeout: 2000
  ConnectionTimeout: 2000
  OkToRetryOnAllOperations: true
  MaxAutoRetriesNextServer: 1 # 当前实例全部失败后可以换1个实例再重试
  MaxAutoRetries: 2 # 在当前实例只重试2次
  http:
    client:
      enabled: true

以上配置最多会调用6次((MaxAutoRetries+1)*(MaxAutoRetriesNextServer+1)),也就是最多会重试5次。

Feign

eureka-client还是上面的例子没变化,主要看service-feign服务:
controller:

@RestController
public class TestController {
	
	private final TestFeign testFeign;

	@Autowired
	public TestController(TestFeign testFeign) {
		this.testFeign = testFeign;
	}

	@GetMapping("/test")
	public String test() {
	    return testFeign.test();
	}
}

feign接口:

@FeignClient("eureka-client")
public interface TestFeign {

	@RequestMapping("/test")
	String test();
}

配置文件还是基本的配置。
运行如下:

在这里插入图片描述
feign默认的超时时间是1秒,重试1次。在我查找资料的过程当中,发现一些博客是写feign默认重试5次(包括首次),但在我的测试中都不会出现重试5次的情况,几经搜查,在一篇大佬博客中找到答案:由于feign本身也具备重试能力,在早期的Spring Cloud中,Feign使用的是 feign.Retryer.Default#Default() ,而它默认重试5次。

public interface Retryer extends Cloneable {

  /**
   * if retry is permitted, return (possibly after sleeping). Otherwise propagate the exception.
   */
  void continueOrPropagate(RetryableException e);

  Retryer clone();

  public static class Default implements Retryer {

    private final int maxAttempts;
    private final long period;
    private final long maxPeriod;
    int attempt;
    long sleptForMillis;

    public Default() {
      this(100, SECONDS.toMillis(1), 5);
    }

    public Default(long period, long maxPeriod, int maxAttempts) {
      this.period = period;
      this.maxPeriod = maxPeriod;
      this.maxAttempts = maxAttempts;
      this.attempt = 1;
    }
    ...
}

但Feign整合了Ribbon,Ribbon也有重试的能力,此时,就可能会导致行为的混乱。所以C版本及以后的版本重试机制改为feign.Retryer#NEVER_RETRY,即关闭了feign自身的重试机制。

/**
   * Implementation that never retries request. It propagates the RetryableException.
   */
  Retryer NEVER_RETRY = new Retryer() {

    @Override
    public void continueOrPropagate(RetryableException e) {
      throw e;
    }

    @Override
    public Retryer clone() {
      return this;
    }
  };

如需使用重试,只需使用Ribbon的重试配置,超时设置也是配ribbon的,即

ribbon:
  ReadTimeout: 2000
  ConnectionTimeout: 2000
  OkToRetryOnAllOperations: true
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 2

feign的超时设置其实还有一层Hystrix的,这个留下一篇再讲。

demo地址

参考链接:
Spring Cloud各组件重试总结
feign 的重试机制

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud是一个用于构建分布式系统的开发工具集合,它提供了许多有用的组件,包括ZuulRibbonHystrix和@FeignClient。 ZuulSpring Cloud中的网关服务,它可以将各个微服务的请求路由到相应的微服务上。Zuul具有负载均衡和过滤器等功能,可以对请求进行拦截和处理。 Ribbon是一个负载均衡器,它可以根据负载情况将请求分发给不同的微服务实例。Ribbon可以与Eureka等注册中心配合使用,动态地获取可用的服务实例列表,并根据一定的负载均衡策略选择合适的实例。 Hystrix是一个容错和延迟容忍的库,可以帮助我们构建稳定的分布式系统。它可以防止由于某一微服务的故障或延迟而导致整个系统的崩溃。通过为每个外部服务的调用添加断路器,Hystrix可以在外部服务不可用时提供备选方案,并且可以对外部服务的调用进行监控和度量。 @FeignClient是一个用于声明式REST客户端的注解。通过在接口中添加@FeignClient注解,并指定要访问的微服务名称,我们可以方便地进行REST调用。Feign会根据接口定义自动生成实现类,并将请求发送到相应的微服务。 综上所述,Spring Cloud中的ZuulRibbonHystrix和@FeignClient是用于构建分布式系统的重要组件。它们可以帮助我们解决微服务架构中的路由、负载均衡、容错和服务间调用等问题。利用这些组件,我们可以更方便地构建可靠、高效的分布式系统。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值