本文主要介绍 Spring Cloud Gateway 的路由熔断、路由重试和高可用。
在前面学习 Hystrix 的时候,我们知道 Hystrix 有服务降级的能力,即如果服务调用出现了异常,则执行指定的 fallback 方法。Spring Cloud Gateway 也融合了 Hystrix,可以为我们提供路由层面服务降级。我们就来看看如何来做。
在之前 gateway 工程的基础上引入 Hystrix 依赖
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
配置文件添加 Filter
spring:
cloud:
gateway:
routes:
- id: service_customer
uri: lb://CONSUMER
predicates:
- Path=/customer/**
filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/fallback
Hystrix 支持两个参数:
HystrixCommand
的名字forward:
schemed 的最后在 gateway 的项目中创建一个 endpoint:/fallback
@RestController
public class FallbackController {
@GetMapping("/fallback")
public String fallback() {
return "Hello World!\nfrom gateway";
}
}
仅做以上配置就 OK 了,如果需要更强大的功能,可以参考HystrixGatewayFilterFactory
进行自定义。
虽然目前官方文档上还没有关于重试的内容,不过我们能在代码中找到RetryGatewayFilterFactory
。但是据我测试这个好像还是有些问题。
理论上只要在 application.xml 里这么配置就可以了
spring:
cloud:
gateway:
routes:
- id: service_customer
uri: lb://CONSUMER
predicates:
- Path=/customer/**
filters:
- Retry=5
为了测试我们再改造一下 consumer 中的 HelloController,我们让它在方法入口处打印 log,然后 sleep 10 分钟
@CommonsLog
@RequestMapping("/hello")
@RestController
public class HelloController {
@Autowired
HelloRemote helloRemote;
@GetMapping("/{name}")
public String index(@PathVariable("name") String name) throws InterruptedException {
log.info("the name is " + name);
if ("retry".equals(name)) {
TimeUnit.MINUTES.sleep(10);
}
return helloRemote.hello(name) + "\n" + new Date().toString();
}
}
但是实际测试发现,当 Gateway 向 consumer 请求的时候,根本就没有超时这个概念,我也没找到能设置超时的地方。唯一能找到的一个超时是通过 Hystrix 设置(参考 github),比如上边我们HystrixCommand
的 name 是 fallbackcmd,那么就设置如下
hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000
但是配置了 Hystrix 之后,超时就直接 fallback 了,所以根本轮不到 retry
java.lang.NullPointerException: null
at org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory.lambda$null$0(RetryGatewayFilterFactory.java:55) ~[spring-cloud-gateway-core-2.0.0.RC1.jar:2.0.0.RC1]
那我 Hystrix 只配置 name 不配置 fallbackUri 行不行?也不行。
虽然这样确实 retry 了,在 consumer 的 log 中能看到多条打印,但是在 gateway 里边却报错了
com.netflix.hystrix.exception.HystrixRuntimeException: fallbackcmd command executed multiple times - this is not permitted.
所以看样子这个 Retry 现在还不能用,等有时间了再研究下。
我们实际使用 Spring Cloud Gateway 的方式如上图,不同的客户端使用不同的负载将请求分发到后端的 Gateway,Gateway 再通过 Eureka 调用后端服务,最后对外输出。因此为了保证 Gateway 的高可用性,前端可以同时启动多个 Gateway 实例进行负载,在 Gateway 的前端使用 Nginx 或者 F5 进行负载转发以达到高可用性。
Spring Cloud Gatewa - Hystrix GatewayFilter Factory
示例代码可以从 Github 获取:https://github.com/zhaoyibo/spring-cloud-study