Spring cloud Gateway 新一代网关
Spring cloud Gateway 新一代网关
1、简介
Cloud全家桶中有一个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;但是在springBoot2.x中,zuul升级一直没有完善,SpringCloud最后自己研发了一个网关替代Zuul,那就是SpringCloud Gateway。
Gateway提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤功能,例如:反向代理、鉴权、限流、熔断、日志监控等。
SpringCloud gateway是基于WebFlux框架实现的,而webFlux框架底层则使用了高性能的Reactor模式通信框架Netty。目标提供统一的路由方式且基于Filter链的方式提供网关的基本功能,例如安全、监控指标,和限流。
springCloud Gateway具有如下特性:
1:基于Spring Framework5, Project Reactor和SpringBoot2.0进行构建。
2:动态路由:能够匹配任何请求属性。
3:可以对路由指定Predicate(断言)和Filter过滤器。
4:集成Hystrix的断路器功能;
5:集成springcloud服务发现功能;
6:请求限流功能
7:支持路径重写
8:易于编写的Predicate(断言)和Filter过滤器。
Zuul与Gateway的区别?
Zuul1.x是一个阻塞I/O的API网关,不支持任何长连接(如WebSocket),性能较差。Zuul2.x springCloud没有集成。
SpringCloud Gateway基于Netty使用非阻塞API,支持websocket,并与spring紧密集成。
Route(路由):
路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由。
Predicate(断言):
开发人员可以匹配HTTP请求中的所有内容(例如请求头和请求参数),如果请求与断言匹配则进行路由。
Fileter(过滤):
指的是Spring框架中的GatewayFilter实例,使用过滤器 ,可以在请求被路由前或后对请求进行修改。
使用:
<!-- springCloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
yml:
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_route # payment_route 路由的ID,必须唯一
uri: http://localhost:8001 # 匹配后端提供路由的地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_route2 # payment_route2 路由的ID
uri: http://localhost:8001 # 匹配后端提供路由的地址
predicates:
- Path=/payment/lb./**
Gateway网关的2种配置方式:
1:在yml中配置,如上。
2:代码中注入RouteLocator的Bean:
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes);
// http://news.baidu.com/guonei
routes.route("dw_router",
r -> r.path("/guonei")
.uri(" http://news.baidu.com")).build();
return routes.build();
}
}
通过微服务名实现动态路由:
1:默认情况下Cateway会根据注册中新的服务列表上注册的微服务名创建动态路由进行转发,从而实现动态路由的功能。
修改yml:
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_route # payment_route 路由的ID,必须唯一
#uri: http://localhost:8001 # 匹配后端提供路由的地址
uri: lb://cloud-payment-service # 匹配后端提供路由的地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_route2 # payment_route2 路由的ID
#uri: http://localhost:8001 # 匹配后端提供路由的地址
uri: lb://cloud-payment-service # 匹配后端提供路由的地址
predicates:
- Path=/payment/lb/**
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka
register-with-eureka: true
fetch-registry: true
instance:
hostname: cloud-gateway-service
路由Predicates工厂:
Predicates就是为了实现一组匹配规则让请求过来找到对应的Route进行处理。
gateway限流:
Spring Cloud Gateway内置的 RequestRateLimiterGatewayFilterFactory
提供限流的能力,基于令牌桶算法实现。目前,它内置的 RedisRateLimiter
,依赖Redis存储限流配置,以及统计数据。当然你也可以实现自己的RateLimiter,只需实现 org.springframework.cloud.gateway.filter.ratelimit.RateLimiter
接口,或者继承 org.springframework.cloud.gateway.filter.ratelimit.AbstractRateLimiter
。
漏桶算法:
想象有一个水桶,水桶以一定的速度出水(以一定速率消费请求),当水流速度过大水会溢出(访问速率超过响应速率,就直接拒绝)。
漏桶算法的两个变量: •水桶漏洞的大小:rate•最多可以存多少的水:
burst 令牌桶算法:
系统按照恒定间隔向水桶里加入令牌(Token),如果桶满了的话,就不加了。每个请求来的时候,会拿走1个令牌,如果没有令牌可拿,那么就拒绝服务。
1、加入maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
2 、写配置:
spring:
cloud:
gateway:
routes:
- id: after_route
uri: lb://user-center
predicates:
- TimeBetween=上午0:00,下午11:59
filters:
- AddRequestHeader=X-Request-Foo, Bar
- name: RequestRateLimiter
args:
# 令牌桶每秒填充平均速率
redis-rate-limiter.replenishRate: 1
# 令牌桶的上限
redis-rate-limiter.burstCapacity: 2
# 使用SpEL表达式从Spring容器中获取Bean对象
key-resolver: "#{@pathKeyResolver}"
redis:
host: 127.0.0.1
port: 6379
在上面的配置文件,配置了 redis的信息,并配置了RequestRateLimiter的限流过滤器,该过滤器需要配置三个参数:
- burstCapacity:令牌桶总容量。
- replenishRate:令牌桶每秒填充平均速率。
- key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
IP限流:
获取请求用户ip作为限流key。
@Bean
public KeyResolver hostAddrKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
用户限流
获取请求用户id作为限流key。
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
接口限流
获取请求地址的uri作为限流key。
@Bean
KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}