Spring Cloud Alibaba Gateway - 服务网关

989 阅读7分钟

🔥在微服务架构中,每个服务都是一个可以独立开发的组件和运行的组件,而一个完整的微服务架构由一系列的独立运行的微服务组成,比如:订单服务提供订单业务场景有关功能、商品服务提供商品展示展示功能,各个微服务之间通过轻量级通信机制REST API或者RPC完成通信,对于客户端来说,可能需要调用商品服务、订单服务、库存服务等对个服务完成数据的渲染,但是客户端通过调用多个服务获取数据时,会存在一些问题:

  • 客户端需要发起多次请求,增加了网络通信的成本及客户端处理的复杂性。
  • 服务鉴权会分布在每个服务中处理,客户端对于每个服务的调用都需要重复鉴权。
  • 在后端架构中,可能不同的微服务采用的协议不同,比如:HTTP、RPC,客户daunt需要调用的多个服务,需要对不同的协议进行适配。

Spring Cloud Gateway网关的目的是提供一种简单而有效的方法来路由到API,类似于门面,所以外部的请求都需要经过网关这一层,然而,网关也不仅是值做一个请求转发及服务的整合,有了网关,它还可以提供一下功能:

一、网关的作用

  • 针对所以的请求进行统一鉴权、限流、熔断、分发、跨域配置、日志等。
  • 统一的错误码处理。
  • 请求转发,并且可以实现基于网关内、外网隔离。
  • 协议转化,针对后端的多种不同协议,在网关层统一处理后HTTP对外提供服务,用过Dubbo框架的读者应该知道,针对Dubbo服务还需要提供一个Web应用进行协议转化。

Spring Cloud Gateway是Spring官方团队研发的API网关技术,目的是取代zuul为新一代微服务提供一种简单高效的网关。

1.1 统一网关鉴权

统一认证鉴权主要包括如下两部分:

  • 客户端身份认证:判断是否是合法用户,一般做法是使用账号和密码进行验证,对于一些复杂的认证场景会采用加密算法来实现,比如公钥、私钥。
  • 访问权限控制:身份认证和访问权限一般是相互联系的,当身份认证通过后,就需要判断还用户是否有访问的该资源的权限,或者该用户的访问权限是否被限制了。

在以往的单体项目中,客户端的认证及访问权限控制相对比较简单,一般都是通过session的方式来保存用户的信息,但是在微服务架构中,单体应用被拆分为多个服务,鉴权服务就会变得复杂起来。

🤩首先要解决的问题是:

1️⃣ 原来的单体应用中的session方式已经无法使用微服务场景。
2️⃣ 该如何实现对每个微服务进行鉴权。

对于第一个问题,目前已经有很多非常成熟的解决方案了,比如:JWTOauth2(开放API)等,对于第二个问题,常见的做法是把鉴权功能单独抽出做一个统一认证服务,所有的微服务在被访问之前,先访问该认证服务进行鉴权,这种解决方案看是合理,但是在实际的应用中,一个业务场景可能会调用多个微服务无,就会造成对一次请求会进行多次鉴权操作,增加了网络通信开销

如下图所示,新增API网关服务之后,在网关层进行请求拦截,获取请求中附带的用户身份信息,调优统一认证中心对进行进行身份认证,在确认身份之后再检查是否有资源的访问权限。

网关鉴权.jpg

1.2 灰度发布

在如今这个互联网时代,产品的需求迭代是非常快,很多公司都会采用一周一发版的迭代模式,在这种高频率的迭代模式下,会伴随着一定的风险,比如:

  • 新发布的代码出现API兼容性问题。
  • 新的功能发布之后,用户是否能接受,如果不能,会造成用户流失。
  • 代码中的隐藏bug,导致线上故障。

为了避免这些问题,对于比较大的功能改动版本一般都会采用灰度发布的方式来实现平滑过渡。

所谓灰度发布,是指在黑与白之间,能够平滑过渡的一种发布方式。在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

对于应用系统来说,无非就是将新的功能发布在特定的灰度机器上,然后再根据特定的规则将部分请求路由到灰度服务器上。

网关是所以客户端请求的入口,因此在网关层可以通过灰度规则进行部门流量的路由,从而实现灰度发布,如下入所示,网关对请求进行拦截之后,会根据分流引擎的分流规则进行请求的路由。

灰度发布.png

二、网关的原理分析

Spring Cloud Gateway的请求处理过程如下图所示,其中有几个非常重要的概念。

  • 路由(Route):它是网关的基本组件,有iduriorderpredicate集合atewayFilters集合组成
  • 谓词(Predicate):它是Java8中引入的函数式接口,提供了断言的功能,他乐意匹配HTTP请求中的任何内容,如果Predicate的聚合判断结构为true,则意味着该请求会被当前Route根据本身的路由规则进行转发。
  • 过滤器(Filter):为请求提供前置和后置过滤。

Spring Cloud Gateway请求处理过程.jpg

Spring Cloud Gateway启动时基于Netty Server监听一个指定的端口(该端口可以通过server.port进行自定义),当客户端发送一个请求到网关时,网关会根据一系列Predicate的匹配结构决定访问哪个Route路由,然后根据过滤器链进行请求的处理,过滤器链可以在请求发送到后端服务器之前和之后执行,也是首先执行Pre过滤器链,然后将请求转发到后端服务器,最好执行`Post过滤器链。

2.1 Route源码分析

public class Route implements Ordered {
    private final String id;
    private final URI uri;
    private final int order;
    private final AsyncPredicate<ServerWebExchange> predicate;
    private final List<GatewayFilter> gatewayFilters;
    private final Map<String, Object> metadata;

    private Route(String id, URI uri, int order, AsyncPredicate<ServerWebExchange> predicate, List<GatewayFilter> gatewayFilters, Map<String, Object> metadata) {
        this.id = id;
        this.uri = uri;
        this.order = order;
        this.predicate = predicate;
        this.gatewayFilters = gatewayFilters;
        this.metadata = metadata;
    }

    public static Route.Builder builder() {
        return new Route.Builder();
    }
}

在application.yml配置文件中添加Gateway的路由配置:

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        predicates:
        - Path=/foo/** # 路径匹配
        filters:
        - StripPrefix=1 # 跳过前缀
        - AddRequestHeader=X-Request-Foo, Bar-{segment}
server:
  port: 8088

上述配置中字段的含义说明如下:

  • id:自定义路由ID,保持唯一。
  • uri:目标服务地址,支持普通的URI及lb://应用注册服务名称,后置表示总注册中心获取集群服务地址。
  • predicates:路由条件,根据匹配的结果决定是否执行该请求的路由。
  • filters:过滤规则,包含pre和post的过滤,其实StripPrefix=1,标识Gateway根据该配置的值去启动应用。