spring-cloud-gateway是一个库,可以在spring webflux之上建立一个API网关,它的目的是提供一个简单,有效的方式去路由到APIS并且提供:安全、监控和弹性。gateway构建于spring boot2.x,spring webFlux,and Project Reactor,所以,许多同步库如spring Data和spring security不适用于gateway项目中。因为gateway是异步非阻塞的。
gateway要求spring boot和spring webFlux提供Netty运行环境。它不能工作在传统的servlet容器或打成一个War包。
1、能够对任意的请求属性进行路由匹配
2、能对路由进行断言和过滤
3、集成了熔断器
4、集成了spring-cloud-discoveryclient
5、很容易的写断言和过滤
6、限流
7、路径重写
1、Route。是构建网关的基本模块,他是ID,目标URL,一系列的断言和过滤器组成,如果断言为true,则匹配该路由
2、Rredicate。参考的是Java8的Predicate,开发人员可以匹配HTTP请求中的所有内容,如果请求与断言相匹配则进行路由
3、Filter。指的是spring框架中GatewayFileter的实例,使用过滤器,可以在请求被路由前由前或者之后对请求进行修改。
客户端将请求发给spring cloud gateway,如果gateway handle mapping 确定这个请求和一个路由匹配,它将此请求发给 gateway web handle. 这个 handle 运行这个请求,通过一个filter chain,这个 filter chain在请求路由前后都能执行。
gateway作为网关,与其他网关技术不同的是它能实现限流。gateway使用的是令牌桶算法实现限流。常见的限流算法有:
1、计数器算法:以QPS为100举例,如果1秒钟内钱200ms请求数量到达了100,后面800ms中的请求都会被拒绝,这种情况称为”突刺现象“
2、漏桶算法:可以解决突刺现象。比如创建一个很大的队列来接收请求,一个较小的线程池来处理请求。但是也有极限情况,当队列满了时, 请求也会拒绝掉。
3、令牌桶算法:可以说是漏桶算法的改进。在桶中放令牌,请求获取令牌后才能继续执行。如果桶中无令牌,请求可以选择进行等待或直接拒绝。
在项目中使用gateway网关做限流一般结合的redis,使用令牌桶算法。
gateway包含了许多内置的路由断言工厂。所有的这些断言匹配不同的HTTP请求属性。你能组合这些路由断言工厂。我们一般是在配置文件中配置predicates,当然我们也可以自定义Predicate,如下:
@Component
public class CustomeRoutePredicateFactory extends AbstractRoutePredicateFactory<PathRoutePredicateFactory.Config> {
public CustomeRoutePredicateFactory() {
super(PathRoutePredicateFactory.Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(PathRoutePredicateFactory.Config config) {
System.out.println("TokenRoutePredicateFactory Start...");
return exchange -> {
ServerHttpRequest request = exchange.getRequest();
//take information from the request to see if it
//matches configuration.
return matches(config, request);
};
}
private boolean matches(PathRoutePredicateFactory.Config config, ServerHttpRequest request) {
System.out.println(request.getBody());
RequestPath path = request.getPath();
if(path.toString().contains("gateway")) return false;
return true;
}
}
yml
routes:
- id: path_route
uri: lb://PROVIDER # lb的意思是负载均衡
predicates:
- Custome=/gateway/** #这个Custome就是自定义类CustomeRoutePredicateFactory的前缀,仿照PathRoutePredicateFactory写的
filters:
- name: Hystrix #表示filter中使用Hystrix来做熔断降级
args:
name: fallbackcmd #名字唯一即可
fallbackUri: forward:/defaultfallback #在本gateway中产生的异常或超时将调用本gateway中的control层中的defaultfallback
上面的逻辑是,获取路径值,如果存在gateway字符串,则返回false。
gateway给我们提供了很多内置的Predicate,如断言时间的 AfterRoutePredicateFactory、BeforeRoutePredicateFactory…,断言cookie的CookieRoutePredicateFactory,断言请求头的HeaderRoutePredicateFactory,一般见其名知其意,且yml中配置时只需要写前缀即可,且一般有两个参数,第一个值一般都是Java的正则表达式。例如
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p #Cookie就是前缀名
gateway的filter有三种:全局Filter、默认Filter和自定义Filter。
全局Filter一般是我们定义,全局的filter一般要实现GlobalFilter 和Orderd,我们可以设置getOrder()方法来设置当前Filter的执行权重。order值越小,请求服务前的优先级越高,服务返回后执行的优先级越低。
如下
@Bean
public GlobalFilter customGlobalFilter() {
return (exchange, chain) -> exchange.getPrincipal()
.map(Principal::getName)
.defaultIfEmpty("Default User")
.map(userName -> {
//adds header to proxied request
exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
return exchange;
})
.flatMap(chain::filter);
}
@Bean
public GlobalFilter customGlobalPostFilter() {
return (exchange, chain) -> chain.filter(exchange)
.then(Mono.just(exchange))
.map(serverWebExchange -> {
//adds header to response
serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
return serverWebExchange;
})
.then();
}
gateway也为我们提供了很多的内置Filter,即默认的Filter,像AddRequestHeaderGatewayFilter,AddRequestParameterGatewayFilter等等。在yml中配置也只需要写前缀即可,如下
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=red, blue
下面讲几个常用的gateway内置的Filter:ForwardRoutingFilter和ReactiveLoadBalancerClientFilter
ForwardRoutingFilter:这个过滤器将URI视为是可改变的属性。当URL有forward修饰时,例如:forward://localendpoint,它会使用spring的DispatcherHandle来处理请求,换句话说,就是用DispatcherHandle来处理forward请求转发。
ReactiveLoadBalancerClientFilter:就是用来负载均衡的。当URL有lb时,例如:lb://myservice,它使用springCloud的ReactLoadBalancer去解析服务名为myservice的微服务(将这个myservice解析为实际的主机和端口,并替换当前的URI),找到这个微服务的集群,并负载均衡到某一台,执行服务。
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
注意:gateway支持所有的loadbalancer特性。
先看看官网的例子,如下
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingServiceEndpoint
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis
- RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint
表示如果发生了fallback,则重定向到fallbackUri地址中的controller。正常的话,是到uri中的controller
当然,你也可以使用配置的方式,如下
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint")
.filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis"))
.rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088")
.build();
}
熔断器也可以这样写,没有fallback或处理在gateway应用中,而是有一个注册在主机9994端口下的应用,这个应用可以处理fallback。
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb://ingredients
predicates:
- Path=//ingredients/**
filters:
- name: CircuitBreaker
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback
下面看看我们自己设置的熔断降级,如下
//在当前gateway中的controller,如果Yml中没有配置其他主机的fallback方法,如果配置了,则该方法配置在另外的主机上。
@Configuration
public class CircuitConfig {
@HystrixCommand(commandKey = "gatewayCommand",fallbackMethod = "gatewayFallback",commandProperties = {
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED,value = "true"),
@HystrixProperty(name =HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,value = "10000"),
@HystrixProperty(name =HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value = "40"),
@HystrixProperty(name =HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value = "5"),
})
public String gatewayCommand(){
return "gatewayCommand method..";
}
public String gatewayFallback(){
return "gatewayFallback method..";
}
gateway的yml
routes:
- id: path_route
uri: lb://PROVIDER # lb的意思是负载均衡
predicates:
- Custome=/gateway/**
filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/defaultfallback
注意,当前fallbackuri只能使用forward!如果没配置其他的处理fallback的主机,则重定向到当前网关主机的controller路径。
需要actuator的依赖。
一般gateway的路由信息是配置注册中心,我们可以使用原始的手工方式刷新路由缓存。使用post请求/actuator/gateway/refresh 即可。当然这需要导入spring的actuator依赖
你也可以检索gateway中所有的路由信息,以手工方式。使用get请求/actuator/gateway/routes
你也可以检索某一个路由信息,使用get请求/actuator/gateway/routes/{id}
总之,可以使用actuator来CRUD路由。
1、gateway网关作为整个项目的最上层,其实就是对请求的处理,细化说有:请求路由转发,限流,熔断降级和负载均衡等。但是在项目中一般使用的请求转发和负载均衡。
2、gateway中限流使用的是令牌桶算法。
3、gateway的熔断降级只能在本网关内出现的异常和超时,如果正常请求到别的微服务,而在别的微服务中出现的超时和异常,配置在gateway网关中的熔断降级不起效。
4、gateway使用的异步非阻塞的模型,底层使用的Netty框架,可和springwebFlux、springMvc结合使用。
5、gateway中的Fileter可以理解为是spring中的Aop机制中的环绕通知。有前置和后置,针对请求服务前后而言。Filter的order值越小,执行前置的优先级越大,执行后置的优先级越小。