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、网关处理流程
- 首先,客户端请求发送到网关,这个时候先由Gateway Handler Mapping判断请求与路由是否匹配(通过Predicate实现),如果匹配的请求,则进入下一步。
- 匹配的请求,将其发送到Gateway web handler进行处理。
- Gateway web handler处理时,先经由“pre”过滤器进行处理。
- 然后,再经过代理服务进行处理。
- 最后再经由“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容器中,然后通过配置文件,可以被限流过滤器读取并使用。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68772.html