Spring Cloud入门之服务网关Spring Cloud Gateway

Spring Cloud 之 服务网关Spring Cloud Gateway

1、Spring Cloud Gateway 简介

  Spring Cloud Gateway是Spring Cloud官方推出的网关框架,用来取代Zuul网关(指Zuul 1.x,是一个基于阻塞I/O的API Gateway)。Spring Cloud Gateway建立在Spring5、Project Reactor和SpringBoot2之上,使用非阻塞API。Spring Cloud Gateway还支持WebSocket,并且与Spring紧密集成,拥有更好的开发体验。网关常见的功能除了路由转发之外,还有权限校验、限流控制等功能。

2、网关处理流程

  1. 首先,客户端请求发送到网关,这个时候先由Gateway Handler Mapping判断请求与路由是否匹配(通过Predicate实现),如果匹配的请求,则进入下一步。
  2. 匹配的请求,将其发送到Gateway web handler进行处理。
  3. Gateway web handler处理时,先经由“pre”过滤器进行处理。
  4. 然后,再经过代理服务进行处理。
  5. 最后再经由“post”过滤器进行处理。

在Spring Cloud Gateway中内置了很多Predicate和Filter类型。

3、网关服务搭建

  我这里专门创建了一个gateway-server服务,用来搭建网关服务。

3.1、添加依赖

  主要是添加spring-cloud-starter-gateway依赖,这是搭建网关需要的依赖,同时引入了spring-cloud-starter-netflix-eureka-client依赖,主要实现服务的注册和发现(注册中心使用之前搭建的即可)。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
3.2、application.properties修改

  这里除了增加了应用名称、端口号、Eureka服务注册外,主要还添加了两个服务的路由配置,具体如下:

spring.application.name=gateway-server
server.port=8100

#设置与Eureka Server交互的地址。
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8000/eureka/

spring.cloud.gateway.routes[0].id=gateway-clientA
spring.cloud.gateway.routes[0].uri=lb://gateway-clientA
spring.cloud.gateway.routes[0].predicates[0]= Path=/clientA/**
spring.cloud.gateway.routes[0].filters[0]= StripPrefix=1

spring.cloud.gateway.routes[1].id=gateway-clientB
spring.cloud.gateway.routes[1].uri=lb://gateway-clientB
spring.cloud.gateway.routes[1].predicates[0]= Path=/clientB/**
spring.cloud.gateway.routes[1].filters[0]= StripPrefix=2

  其中,

  • spring.cloud.gateway.routes[0].id 自定义的路由ID
  • spring.cloud.gateway.routes[0].uri=lb://gateway-clientA 目标服务地址
  • spring.cloud.gateway.routes[0].predicates[0]= Path=/clientA/** 路由条件,这里表示访问http://localhost:8100/clientA/xxx 时,会转发到gateway-clientA目标服务上
  • spring.cloud.gateway.routes[0].filters[0]= StripPrefix=1 是否去除前缀,在当前路径匹配中表示去掉是否去掉服务名称,比如/gateway-clientA,其中StripPrefix=1表示去掉,StripPrefix=2表示不去掉。后续测试两个服务的时候,可以看出其中区别。
3.3、 启动类

  启动类,是一个普通的SpringBoot启动类,网关服务也不需要额外增加启动网关服务的注解,这里只需要增加了服务注册发现的注解@EnableDiscoveryClient即可。

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayServerApplication.class, args);
    }

}

4、代理服务(实际服务提供者)

  这里为了演示API网关服务的使用,我们准备了两个应用gateway-clientA和gateway-clientB来进行测试。这两个服务是普通的SpringBoot应用,分别提供了一个测试接口,具体可以参考源码。

5、启动、测试

  分别启动网关服务和两个测试服务,访问gateway-clientA服务时,可以通过http://localhost:8100/clientA/provider 进行访问,这里访问了网关服务的,然后由服务网关进行路由转发到gateway-clientA应用实例上。访问gateway-clientB服务时,可以通过http://localhost:8100/clientB/gateway-clientB/provider 进行访问,和访问gateway-clientA的区别是在访问路径上增加了服务名称,这个主要是因为StripPrefix参数决定的。

6、基于服务发现进行路由配置

  如果我们有非常多的微服务模块,每个服务模块都通过前面的这种方式进行配置会非常的麻烦,有什么方式可以避免这种配置呢?我们可以基于注册服务,启用自动的路由配置。

  其实这种方法也很简单,因为前面我们的实例已经引入了Eureka注册中心,所以这里我们只需要修改网关服务的配置文件即可,如下所示:

spring.application.name=gateway-server
server.port=8100

#设置与Eureka Server交互的地址。
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8000/eureka/

spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.discovery.locator.lower-case-service-id=true

  其中,

  • spring.cloud.gateway.discovery.locator.enabled=true 开启服务注册和发现的功能,即Spring Cloud Gateway自动根据服务发现为每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务。
  • spring.cloud.gateway.discovery.locator.lower-case-service-id=true 将请求路径上的服务名配置为小写。需要注意的是,这里是把服务名称全部转化成小写,不论是服务注册时变为大写还是在定义服务名称的时候就有的大写(本意应该是为了处理服务注册的时候,向注册中心注册时将服务名转成大写的问题)。

  修改配置后,重新启动网关服务,这个时候再分别访问http://localhost:8100/gateway-clienta/provider 和 http://localhost:8100/gateway-clientb/provider 就可以进行相关api接口的访问了。

7、熔断降级

  Spring Cloud Gateway支持Hystrix过滤器的应用,这里选择集成Hystrix实现服务的熔断降级。

  首先,添加Hystrix依赖,如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

  然后,修改配置如下:

spring.cloud.gateway.routes[1].id=gateway-clientB
spring.cloud.gateway.routes[1].uri=lb://gateway-clientB
spring.cloud.gateway.routes[1].predicates[0]= Path=/clientB/**
spring.cloud.gateway.routes[1].filters[0]= StripPrefix=2
#熔断降级
spring.cloud.gateway.routes[1].filters[1].name=Hystrix
spring.cloud.gateway.routes[1].filters[1].args.name=fallback
spring.cloud.gateway.routes[1].filters[1].args.fallbackUri=forward:/fallback

 &esmp;其中,

  • fallbackUri: forward:/fallback配置了 fallback 时要会调的路径,当调用 Hystrix 的 fallback 被调用时,请求将转发到/fallback这个 URI。

  最后,增加一个回调方法,如下:

@RestController
public class HystrixController {

    @GetMapping("fallback")
    public String fallback(){
        return "Hystrix限流,被降级!";
    }

}

8、请求重试

  根据请求失败类型,可以为服务设置重机制,如下:

spring.cloud.gateway.routes[0].id=gateway-clientA
spring.cloud.gateway.routes[0].uri=lb://gateway-clientA
spring.cloud.gateway.routes[0].predicates[0]= Path=/clientA/**
spring.cloud.gateway.routes[0].filters[0]= StripPrefix=1
#重试
spring.cloud.gateway.routes[0].filters[1].name=Retry
spring.cloud.gateway.routes[0].filters[1].args.retries=3
spring.cloud.gateway.routes[0].filters[1].args.statuses=BAD_GATEWAY
  • retries:重试次数,默认值是 3 次
  • statuses:HTTP 的状态返回码,取值请参考:org.springframework.http.HttpStatus
  • methods:指定哪些方法的请求需要进行重试逻辑,默认值是 GET 方法,取值参考:org.springframework.http.HttpMethod
  • series:一些列的状态码配置,取值参考:org.springframework.http.HttpStatus.Series。符合的某段状态码才会进行重试逻辑,默认值是 SERVER_ERROR,值是 5,也就是 5XX(5 开头的状态码),共有5 个值。

9、限流过滤器

  Spring Cloud Gateway 提供了基于 Redis 的限流方案。为了实现限流功能,我们首先需要添加对应的依赖包spring-boot-starter-data-redis-reactive。如下所示:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>

  然后,修改配置文件,如下:

#redis
spring.redis.host=localhost
spring.redis.password=123456
spring.redis.port=6379

spring.cloud.gateway.routes[0].id=gateway-clientA
spring.cloud.gateway.routes[0].uri=lb://gateway-clientA
spring.cloud.gateway.routes[0].predicates[0]= Path=/clientA/**
spring.cloud.gateway.routes[0].filters[0]= StripPrefix=1
#限流
spring.cloud.gateway.routes[0].filters[2].name=RequestRateLimiter
spring.cloud.gateway.routes[0].filters[2].args.redis-rate-limiter.replenishRate=20
spring.cloud.gateway.routes[0].filters[2].args.redis-rate-limiter.burstCapacity=30
spring.cloud.gateway.routes[0].filters[2].args.key-resolver=#{@ipKeyResolver}

其中,

  • name必须是 RequestRateLimiter,过滤器名称
  • redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求
  • redis-rate-limiter.burstCapacity:令牌桶的容量,允许在一秒钟内完成的最大请求数
  • key-resolver:使用 SpEL 按名称引用 bean,这里主要用来引入实现限流的规则对应的Bean,需要开发者定义

  定义KeyResolver,实现如下:

@Configuration
public class RatelimitConfig {

    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}

  该Bean会被注册到Spring容器中,然后通过配置文件,可以被限流过滤器读取并使用。

猜你喜欢

转载自blog.csdn.net/hou_ge/article/details/111538605