在微服务架构中,下游依赖出现问题如果上游调用方不做请求降级处理,下游的异常依赖没有被隔离,很有可能出现因为一两个服务或者小到一两个接口异常导致上游所有服务不可用,甚至影响整个业务线。请求降级处理目前比较主流的依然是Netfilx
出品的Hystrix
。Hystrix
的工作原理是:
这里不对Hystrix
的细节做更深入分析,而是接着谈谈Spring Cloud Gateway
中如何使用Hystrix
,主要包括内置的Hystrix
过滤器和定制过滤器结合Hystrix
实现我们想要的功能。除了要引入spring-cloud-starter-gateway
依赖之外,还需要引入spring-cloud-starter-netflix-hystrix
。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
Spring Cloud Gateway
版本为当时最新的版本Greenwich.SR1
。我们在使用Spring Cloud Gateway
的时候,注意到过滤器(包括GatewayFilter
、GlobalFilter
和过滤器链GatewayFilterChain
),都依赖到ServerWebExchange
:
public interface GlobalFilter {
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
public interface GatewayFilter extends ShortcutConfigurable {
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
public interface GatewayFilterChain {
Mono<Void> filter(ServerWebExchange exchange);
}
这里的设计和Servlet
中的Filter
是相似的,当前过滤器可以决定是否执行下一个过滤器的逻辑,由GatewayFilterChain#filter()
是否被调用来决定。而ServerWebExchange
就相当于当前请求和响应的上下文。ServerWebExchange
实例不单存储了Request
和Response
对象,还提供了一些扩展方法,如果想实现改造请求参数或者响应参数,就必须深入了解ServerWebExchange
。
我们平时在用SpringMVC
的时候,只要是经过DispatcherServlet
处理的请求,可以通过@ControllerAdvice
和@ExceptionHandler
自定义不同类型异常的处理逻辑,具体可以参考ResponseEntityExceptionHandler
和DefaultHandlerExceptionResolver
,底层原理很简单,就是发生异常的时候搜索容器中已经存在的异常处理器并且匹配对应的异常类型,匹配成功之后使用该指定的异常处理器返回结果进行Response
的渲染,如果找不到默认的异常处理器则用默认的进行兜底(个人认为,Spring在很多功能设计的时候都有这种“有则使用自定义,无则使用默认提供”这种思想十分优雅)。
SpringMVC
中提供的自定义异常体系在Spring-WebFlux
中并不适用,其实原因很简单,两者底层的运行容器并不相同。WebExceptionHandler
是Spring-WebFlux
的异常处理器顶层接口,因此追溯到子类可以追踪到DefaultErrorWebExceptionHandler
是Spring Cloud Gateway
的全局异常处理器,配置类是ErrorWebFluxAutoConfiguration
。
GatewayFilter
的作用域是指定的路由配置,路由配置选项里面需要通过filters指定想要使用的GatewayFilter
列表。我们可以通过自定义GatewayFilter
,做额外的扩展,实现一些内建GatewayFilter
不存在的功能,并且应用到我们的路由配置中。
GlobalFilter
的作用域是所有的路由配置,我们可以通过自定义GlobalFilter
,做额外的扩展,用来实现一些全局的功能。
最近在做老系统的重构,重构完成后新系统中需要引入一个网关服务,作为新系统和老系统接口的适配和代理。之前,很多网关应用使用的是Spring-Cloud-Netfilx
基于Zuul1.x
版本实现的那套方案,但是鉴于Zuul1.x
已经停止迭代,它使用的是比较传统的阻塞(B)IO + 多线程的实现方案,其实性能不太好。后来Spring团队干脆自己重新研发了一套网关组件,这个就是本次要调研的Spring-Cloud-Gateway
。
Spring Cloud Gateway依赖于Spring Boot 2.0, Spring WebFlux,和Project Reactor。许多熟悉的同步类库(例如Spring-Data
和Spring-Security
)和同步编程模式在Spring Cloud Gateway
中并不适用,所以最好先阅读一下上面提到的三个框架的文档。
Spring Cloud Gateway
依赖于Spring Boot
和Spring WebFlux
提供的基于Netty
的运行时环境,它并非构建为一个WAR包或者运行在传统的Servlet
容器中。