本文主要介绍 Spring Cloud Gateway 的路由熔断、路由重试和高可用。
路由熔断
在前面学习 Hystrix 的时候,我们知道 Hystrix 有服务降级的能力,即如果服务调用出现了异常,则执行指定的 fallback 方法。Spring Cloud Gateway 也融合了 Hystrix,可以为我们提供路由层面服务降级。我们就来看看如何来做。
在之前 gateway 工程的基础上引入 Hystrix 依赖
1 2 3 4 | <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> |
配置文件添加 Filter
1 2 3 4 5 6 7 8 9 10 11 12 13 | spring: cloud: gateway: routes: - id: service_customer uri: lb://CONSUMER predicates: - Path=/customer/** filters: - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback |
Hystrix 支持两个参数:
- name:即
HystrixCommand
的名字 - fallbackUri:即 fallback 对应的 uri,这里的 uri 仅支持
forward:
schemed 的
最后在 gateway 的项目中创建一个 endpoint:/fallback
1 2 3 4 5 6 7 8 9 | @RestController public class FallbackController { @GetMapping("/fallback") public String fallback() { return "Hello World!\nfrom gateway"; } } |
仅做以上配置就 OK 了,如果需要更强大的功能,可以参考HystrixGatewayFilterFactory
进行自定义。
路由重试
虽然目前官方文档上还没有关于重试的内容,不过我们能在代码中找到RetryGatewayFilterFactory
。但是据我测试这个好像还是有些问题。
理论上只要在 application.xml 里这么配置就可以了
1 2 3 4 5 6 7 8 9 10 | spring: cloud: gateway: routes: - id: service_customer uri: lb://CONSUMER predicates: - Path=/customer/** filters: - Retry=5 |
为了测试我们再改造一下 consumer 中的 HelloController,我们让它在方法入口处打印 log,然后 sleep 10 分钟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @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,那么就设置如下
1 | hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds=5000 |
但是配置了 Hystrix 之后,超时就直接 fallback 了,所以根本轮不到 retry
1 2 | 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 里边却报错了
1 | 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