Spring Cloud Zuul的fallback优化

简介: Spring Cloud Zuul的fallback优化

如何在Zuul中使用fallback功能

我们在项目中使用Spring cloud zuul的时候,有一种这样的需求,就是当我们的zuul进行路由分发时,如果后端服务没有启动,或者调用超时,这时候我们希望Zuul提供一种降级功能,而不是将异常暴露出来。

在Dalston版本中,Spring cloud zuul提供这种降级功能,操作步骤如下:

  • 在主函数上添加@EnbaleZuulProxy注解。
  • 实现ZuulFallbackProvider接口。

对应ZuulFallbackProvider源码如下:

public interface ZuulFallbackProvider {
  /**
   * The route this fallback will be used for.
   * @return The route the fallback will be used for.
   */
  public String getRoute();
  /**
   * Provides a fallback response.
   * @return The fallback response.
   */
  public ClientHttpResponse fallbackResponse();
}

我们只要实现该接口,并实现public ClientHttpResponse fallbackResponse();方法,也就是说该方法会让我定义一个ClientHttpResponse作为当异常出现时的返回内容。

通过源码我们可知,Zuul提供三个配置文件,每一个配置文件代表用不同种方式进行请求的转发:

  • RestClientRibbonConfiguration
  • OkHttpRibbonConfiguration
  • HttpClientRibbonConfiguration(默认情况)

HttpClientRibbonConfiguration源码如下(只体现涉及fallback模块):

@Configuration
@ConditionalOnRibbonHttpClient
protected static class HttpClientRibbonConfiguration {
  @Autowired(required = false)
  private Set<ZuulFallbackProvider> zuulFallbackProviders = Collections.emptySet();
  @Bean
  @ConditionalOnMissingBean
  public RibbonCommandFactory<?> ribbonCommandFactory(
    SpringClientFactory clientFactory, ZuulProperties zuulProperties
  ) 
  {
    return new HttpClientRibbonCommandFactory(
        clientFactory,
        zuulProperties,
        zuulFallbackProviders
    );
  }
}

通过源码我们可以了解,Zuul将你自定义的fallbackprovider保存在一个Set集合中,并作为HttpClientRibbonCommandFactory构造器的参数。

当zuul在转发请求时最终会利用AbstractRibbonCommand进行处理。通过源码我们知道AbstractRibbonCommand继承了HystrixCommand,所以真正转发请求的业务逻辑是在重写HystrixCommand类的run方法中进行的。

具体源码如下:

@Override
protected ClientHttpResponse run() throws Exception {
  final RequestContext context = RequestContext.getCurrentContext();
  RQ request = createRequest();
  RS response = this.client.executeWithLoadBalancer(request, config);
  context.set("ribbonResponse", response);
  // Explicitly close the HttpResponse if the Hystrix command timed out to
  // release the underlying HTTP connection held by the response.
  //
  if (this.isResponseTimedOut()) {
    if (response != null) {
      response.close();
    }
  }
  return new RibbonHttpResponse(response);
}

我们知道HystrixCommand提供getFallback()方法,这个方法的作用是当run()方法执行出现异常时,会自动调用getFallback()方法,从而完成降级功能。(HystrixCommand是Hystrix的知识,有兴趣的同学可以参照官方git文档)。

由于AbstractRibbonCommand继承了HystrixCommand,它不仅重写了run()方法,而且重写了getFallback()方法,具体源码如下:

@Override
protected ClientHttpResponse getFallback() {
  if(zuulFallbackProvider != null) {
    return zuulFallbackProvider.fallbackResponse();
  }
  return super.getFallback();
}

通过源码我们知道,首先会去判断是否存在自定义的zuulFallbackProvider,如果有,那么直接回调你自定义实现类的fallbackResponse()方法。如果不存在会走hystrixfallback逻辑(有可能直接抛出异常)。

说到这里Zuul的降级原理大致就说完了,细心的朋友可以发现这样的一个问题,就是虽然Zuul提供了降级的回调方法fallbackResponse(),但是这个方法是无参的,也就是说此时虽然你能够给调用端返回一个消息,但是此时你并不知道发生了什么样的异常(也就是说在这里你是获取不到异常信息的)。

Edgware.RC1版本的改进

在Edgware.RC1版本中Spring cloud zuul针对于降级进行了升级,升级的内容主要是解决上面说到的当降级出现时,怎样在降级方法中获取具体的异常信息。

增加了一个接口FallbackProvider,这个接口继承了现有的ZuulFallbackProvider接口,源码如下:

public interface FallbackProvider extends ZuulFallbackProvider {
  /**
      * Provides a fallback response based on the cause of the failed  execution.
      *
      * @param cause cause of the main method failure
      * @return the fallback response
      */
    ClientHttpResponse fallbackResponse(Throwable cause);
}

可以看到这个接口有一个方法,这个方法的参数是Throwable,也就是说此时是用能力获取异常信息的。

接下来改造的内容在AbstractRibbonCommand类中,主要是对原有的getFallback()进行改造,同时增加了一个getFallbackResponse()方法。下面通过源码具体了解下:

@Override
protected ClientHttpResponse getFallback() {
    if(zuulFallbackProvider != null) {
    return getFallbackResponse();
    }
    return super.getFallback();
}

可以看到从原来调用zuulFallbackProvider.fallbackResponse();转而调用内部方法getFallbackResponse()

getFallbackResponse()源码如下:

protected ClientHttpResponse getFallbackResponse() {
  if (zuulFallbackProvider instanceof FallbackProvider) {
    Throwable cause = getFailedExecutionException();
    cause = cause == null ? getExecutionException() : cause;
    if (cause == null) {
      zuulFallbackProvider.fallbackResponse();
    } else {
      return ((FallbackProvider) zuulFallbackProvider).fallbackResponse(cause);
    }
  }
  return zuulFallbackProvider.fallbackResponse();
}

通过源码可知,此时会根据Throwable是否存在来决定走哪种类型的降级方法(原来的还是带有参数的)。

到此Zuul的实现降级的原理以及Edgware.RC1中的改进就介绍完了。

目录
相关文章
|
5月前
|
监控 负载均衡 Java
深入理解Spring Cloud中的服务网关
深入理解Spring Cloud中的服务网关
|
25天前
|
缓存 监控 Java
|
5月前
|
设计模式 监控 Java
解析Spring Cloud中的断路器模式原理
解析Spring Cloud中的断路器模式原理
|
3月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
119 5
|
3月前
|
存储 数据采集 Java
Spring Boot 3 实现GZIP压缩优化:显著减少接口流量消耗!
在Web开发过程中,随着应用规模的扩大和用户量的增长,接口流量的消耗成为了一个不容忽视的问题。为了提升应用的性能和用户体验,减少带宽占用,数据压缩成为了一个重要的优化手段。在Spring Boot 3中,通过集成GZIP压缩技术,我们可以显著减少接口流量的消耗,从而优化应用的性能。本文将详细介绍如何在Spring Boot 3中实现GZIP压缩优化。
376 6
|
5月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
14991 29
|
5月前
|
负载均衡 Java Spring
Spring cloud gateway 如何在路由时进行负载均衡
Spring cloud gateway 如何在路由时进行负载均衡
515 15
|
5月前
|
Java Spring
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
115 3
|
5月前
|
缓存 监控 Java
如何优化Spring Boot应用性能?
【7月更文挑战第16天】如何优化Spring Boot应用性能?
65 2