本文主要介绍 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

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐