背景:
在微服务架构中,通常一个系统会被拆分为多个微服务,面对这么多微服务客户端应该如何去调用呢?如果没有其他更优方法,我们只能记录每个微服务对应的地址,分别去调用,但是这样会有很多的问题和潜在因素。
客户端多次请求不同的微服务,会增加客户端代码和配置的复杂性,维护成本比价高。
认证复杂,每个微服务可能存在不同的认证方式,客户端去调用,要去适配不同的认证,
存在跨域的请求,调用链有一定的相对复杂性(防火墙 / 浏览器不友好的协议)。
难以重构,随着项目的迭代,可能需要重新划分微服务
为了解决上面的问题,微服务引入了 网关 的概念,网关为微服务架构的系统提供简单、有效且统一的API路由管理,作为系统的统一入口,提供内部服务的路由中转,给客户端提供统一的服务,可以实现一些和业务没有耦合的公用逻辑,主要功能包含认证、鉴权、路由转发、安全策略、防刷、流量控制、监控日志等
网关对比
Zuul 1.0 : Netflix开源的网关,使用Java开发,基于Servlet架构构建,便于二次开发。因为基于Servlet内部延迟严重,并发场景不友好,一个线程只能处理一次连接请求。
Zuul 2.0 : 采用Netty实现异步非阻塞编程模型,一个CPU一个线程,能够处理所有的请求和响应,请求响应的生命周期通过事件和回调进行处理,减少线程数量,开销较小
GateWay : 是Spring Cloud的一个全新的API网关项目,替换Zuul开发的网关服务,基于Spring5.0 + SpringBoot2.0 + WebFlux(基于性能的Reactor模式响应式通信框架Netty,异步阻塞模型)等技术开发,性能高于Zuul
Nginx+lua : 性能要比上面的强很多,使用Nginx的反向代码和负载均衡实现对API服务器的负载均衡以及高可用,lua作为一款脚本语言,可以编写一些简单的逻辑,但是无法嵌入到微服务架构中
Kong : 基于OpenResty(Nginx + Lua模块)编写的高可用、易扩展的,性能高效且稳定,支持多个可用插件(限流、鉴权)等,开箱即可用,只支持HTTP协议,且二次开发扩展难,缺乏更易用的管理和配置方式
GateWay
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-starter
Spring Cloud Gateway 是Spring Cloud的一个全新的API网关项目,目的是为了替换掉Zuul1,它基于Spring5.0 + SpringBoot2.0 + WebFlux(基于性能的Reactor模式响应式通信框架Netty,异步阻塞模型)等技术开发,性能于Zuul,官测试,Spring Cloud GateWay是Zuul的1.6倍 ,旨在为微服务架构提供种简单有效的统的API路由管理式。
可以与Spring Cloud Discovery Client(如Eureka)、Ribbon、Hystrix等组件配合使用,实现路由转发、负载均衡、熔断、鉴权、路径重写、志监控等
Gateway还内置了限流过滤器,实现了限流的功能。
设计优雅,容易拓展
基本概念
**路由(Route)**是GateWay中最基本的组件之一,表示一个具体的路由信息载体,主要由下面几个部分组成:
id:路由唯一标识,区别于其他的route
url: 路由指向的目的地URL,客户端请求最终被转发到的微服务
order: 用于多个Route之间的排序,数值越小越靠前,匹配优先级越高
predicate:断言的作用是进行条件判断,只有断言为true,才执行路由
filter: 过滤器用于修改请求和响应信息
核心流程
源码时序图
源码讲解
请求进来先被HttpWebHandlerAdapter拦截到
public HttpWebHandlerAdapter(WebHandler delegate) {
//此处会执行 this.delegate = delegate;, delegate 为 DispatcherHandler
super(delegate);
}
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
if (this.forwardedHeaderTransformer != null) {
request = this.forwardedHeaderTransformer.apply(request);
}
//封装为DefaultServerWebExchange对象
ServerWebExchange exchange = createExchange(request, response);
LogFormatUtils.traceDebug(logger, traceOn ->
exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
//执行到此出,为reactor编程模式
return getDelegate().handle(exchange)
.doOnSuccess(aVoid -> logResponse(exchange))
.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
.then(Mono.defer(response::setComplete));
}
我们看下reactor编程模式的这几个方法
1、getDelegate()
public WebHandler getDelegate() {
//返回DispatcherHandler实例
return this.delegate;
}
2、handle(exchange)
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
//执行该方法
// Flux.fromIterable(this.handlerMappings) 将handlerMappings转化为 Flux
//1、concatMap中调用mapping.getHandler
//2、调用next获取匹配的一个Mono
//3、flatMap中调用invokeHandler方法
//4、flatMap调用handleResult方法
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
2.1、mapping.getHandler
org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler
@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
//1、调用getHandlerInternal,从配置的多个Route中获取匹配的
return getHandlerInternal(exchange).map(handler -> {
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
}
ServerHttpRequest request = exchange.getRequest();
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
return REQUEST_HANDLED_HANDLER;
}
}
return handler;
});
}
2.1.1 getHandlerInternal
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on management port if set and different than server port
if (this.managementPortType == DIFFERENT && this.managementPort != null
&& exchange.getRequest().getURI().getPort() == this.managementPort) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
//1、调用lookupRoute获取合适的Route
// 统一返回FilteringWebHandler处理器
return lookupRoute(exchange)
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isDebugEnabled()) {
logger.debug(
"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
}
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
//统一返回FilteringWebHandler处理器
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for ["
+ getExchangeDesc(exchange) + "]");
}
})));
}
2.1.1.1 lookupRoute
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
//1、this.routeLocator.getRoutes()拿到定义的所有的route信息
//2、Mono.just(route).filterWhen(return r.getPredicate().apply(exchange)) 通过route的断言判断 route是否符合
//3、返回route
return this.routeLocator.getRoutes()
// individually filter routes so that filterWhen error delaying is not a
// problem
.concatMap(route -> Mono.just(route).filterWhen(r -> {
// add the current route we are testing
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
})
// instead of immediately stopping main flux due to error, log and
// swallow it
.doOnError(e -> logger.error(
"Error applying predicate for route: " + route.getId(),
e))
.onErrorResume(e -> Mono.empty()))
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
.next()
// TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("Route matched: " + route.getId());
}
validateRoute(route, exchange);
return route;
});
}
2.2、invokeHandler方法调用
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
//org.springframework.web.reactive.result.SimpleHandlerAdapter#supports
//判断是否WebHandler.class
if (handlerAdapter.supports(handler)) {
//org.springframework.web.reactive.result.SimpleHandlerAdapter#handle
//1、方法内部调用FilteringWebHandler的handle方法
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
2.2.1、handlerAdapter.handle(exchange, handler)
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
WebHandler webHandler = (WebHandler) handler;
//调用FilteringWebHandler#handle方法
Mono<Void> mono = webHandler.handle(exchange);
//返回mono
return mono.then(Mono.empty());
}
2.2.1、FilteringWebHandler#handle
org.springframework.cloud.gateway.handler.FilteringWebHandler#handle
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
//从exchange获取到匹配上的route
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
//获取route定义的过滤器
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
// 排序
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
//形成责任链模式 依次调用filter方法
return new DefaultGatewayFilterChain(combined).filter(exchange);
}