前言
SpringCloud Gateway是一个网关框架,也是现在流行的的一个网关框架,它包括了过滤器、限流、权限、基本路由、整合Eureka 断言predicates 等功能,也会介绍和zuul这个框架的一个对比, Spring Cloud 生态系统中的网关,得力于 Spring Cloud 生态环境,我相信公司用Spring Cloud 框架 一般都会用到这个网关路由框架,因此这个是跑不掉,本篇文章介绍的一部分,当然不可能全部介绍,其他部分可以去官网去查找学习。
什么是网关
网关是一个服务,是访问内部系统的唯一入口,提供内部服务的路由中转,额外还可以在此基础上提供如身份验证、监控、负载均衡、限流、降级与应用检测等功能。
而为什么要说zuul, SpringCloud Gateway 本身就是替换zuul , zuul 本身开始闭源了, 而且还zuul1.x与zuul2.x ;zuul1.x 基于 servlet ,zuul2.x 是基于 servlet 和netty 的开发的。 注定 选定 SpringCloud Gateway 并且 它开发的比较晚,技术选型更好。
这些性能都不是太高,而性能高的还是nginx+lua ,因为涉及到netty 来说 业务线程 去处理,响应式的,也会消耗业务线程,也会消耗性能。都是具体问题具体分析来说,技术选型也需要选择不同的方式;对于普通来说也不是相差特别大。
控制流
Nignx+lua (openresty kong)
业务逻辑 上的 这个 语言上的差异 导致 这个 控制流 处理非常快。
业务网关 收到请求 需要找服务 通过注册中心连接,负载 网关 以及 服务的负载量。 放弃单点的情况,使用 集群的情况。保证一致性 ,限流 要用redis 记录日志等功能,都是系统需要考虑的功能,大系统一定要考虑到的。
像一般的网关io 吞吐量,请求数据,过网关,但返回数据是否过网关,这个东西根据吞吐量,来说一般会过网关,然后获取到客户端数据,然后返回,想lvs 这些会把客户端数据带给服务端,然后不过网关返回客户端数据,这种根据自己的需要选择。各有各的优点和缺点。
Spring Cloud Gateway 与 Zuul 对比
zuul1.x与zuul2.x
Zuul 1.x 基于同步 IO
zuul2.x
基于异步io
zuul1.x 对比 zuul2.x 性能提升
SpringCloud Gateway 使用
断言 predicates
多个断言可以配合使用
通过匹配的方式,访问到具体的路由规则,服务上面。
在服务中配置 对应的 配置打到具体的机器上,
包括多层匹配 ,当上面的匹配到才会到下面的匹配方式
path断言
predicates:
- Path=/mg/**
Query断言
参数值可以写正则,也可以只写参数名
predicates:
- Query=foo,ba.
Method断言
predicates:
- Method=get
Host断言
predicates:
- Host=mashibing.com
Cookie断言
```
predicates:
- Cookie=name,yiming
```
基础使用上,比较简单的,按照具体的规则,写就可以了。
另向路由的方式,会话保持。这是cookie 的保持
基本路由
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
配置文件
spring:
cloud:
gateway:
routes:
- id: xxooroute
uri: http://localhost:8080
filters:
- StripPrefix=2
server:
port: 80
整合Eureka
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
配置
```
spring:
cloud:
gateway:
discovery:
locator:
// 开启从eureka 拉取服务列表 并自动映射
enabled: true
application:
name: myGateWay
eureka:
client:
service-url:
defaultZone: http://euk1.com:7002/eureka/
server:
port: 80
```
负载均衡
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: mdb
predicates:
- Path=/mangodb/**
uri: lb://MDB
filters:
- StripPrefix=1
application:
name: myGateWay
eureka:
client:
service-url:
defaultZone: http://euk1.com:7002/eureka/
server:
port: 80
做匹配的规则,
自定义负载均衡
配置
在代码中做匹配规则,
MDB:
ribbon:
NFLoadBalancerRuleClassName: com.admin.MyRule
package com.admin;
import java.util.List;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.Server;
public class MyRule extends AbstractLoadBalancerRule{
@Override
public Server choose(Object key) {
// TODO Auto-generated method stub
List<Server> list = this.getLoadBalancer().getReachableServers();
System.out.println(list);
// 各种逻辑~~~~
System.out.println("xxoo");
return list.get(0);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
参与到整个过滤规则。
自定义路由
@Bean
public RouteLocator routeLocator (RouteLocatorBuilder locatorBuilder) {
return locatorBuilder.routes()
.route(p ->
p.path("/xxoo")
.filters(f -> f.stripPrefix(1))
.uri("http://ss.com")
)
.route(p ->
p.path("/go")
.filters(f -> f.stripPrefix(1))
.uri("lb://MDB")
)
.build();
}
自定义过滤器
package com.admin;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class MyFilter implements Ordered,GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> queryParams = request.getQueryParams();
List<String> list = queryParams.get("id");
if (null == list || list.size() ==0) {
// 非法请求
// exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//
// return exchange.getResponse().setComplete();
DataBuffer dataBuffer = exchange.getResponse().bufferFactory().wrap("xiake~!!".getBytes());
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().writeWith(Mono.just(dataBuffer));
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 0;
}
}