简介
Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。
特征
- 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
- 动态路由
- Predicates 和 Filters 作用于特定路由
- 集成 Hystrix 断路器
- 集成 Spring Cloud DiscoveryClient
- 易于编写的 Predicates 和 Filters
- 限流
- 路径重写
术语
- Route(路由):这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。
-
Predicate(断言):这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。
-
Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。
Webflux模型
Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。官方结构图:
Webflux虽然可以兼容多个底层的通信框架,但是一般情况下,底层使用的还是Netty,毕竟,Netty是目前业界认可的最高性能的通信框架。而Webflux的Loop线程,正好就是著名的Reactor 模式IO处理模型的Reactor线程,如果使用的是高性能的通信框架Netty,这就是Netty的EventLoop线程。
请求流程
客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
- DispatcherHandler:所有请求的调度器,负载请求分发
- RoutePredicateHandlerMapping:路由谓语匹配器,用于路由的查找,以及找到路由后返回对应的WebHandler,DispatcherHandler会依次遍历HandlerMapping集合进行处理
- FilteringWebHandler : 使用Filter链表处理请求的WebHandler,RoutePredicateHandlerMapping找到路由后返回对应的FilteringWebHandler对请求进行处理,FilteringWebHandler负责组装Filter链表并调用链表处理请求。
filter介绍:
Spring Cloud Gateway,有“pre”和“post”两种方式的filter。客户端的请求先经过“pre”类型的filter,然后将请求转发到具体的业务服务,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端。
Spring Cloud Gateway根据作用范围划分为GatewayFilter和GlobalFilter,二者区别如下:
-
GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上
-
GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器,它为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,系统初始化时加载,并作用在每个路由上。
Spring Cloud Gateway框架内置的GlobalFilter如下:
Spring Cloud Gateway 内置的过滤器工厂一览表如下:
路由规则
Spring Cloud Gateway 的功能很强大,我们仅仅通过 Predicates 的设计就可以看出来,前面我们只是使用了 predicates 进行了简单的条件匹配,其实 Spring Cloud Gataway 帮我们内置了很多 Predicates 功能。
Spring Cloud Gateway 是通过 Spring WebFlux 的 HandlerMapping 做为底层支持来匹配到转发路由,Spring Cloud Gateway 内置了很多 Predicates 工厂,这些 Predicates 工厂通过不同的 HTTP 请求参数来匹配,多个 Predicates 工厂可以组合使用。
Predicate 介绍
Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现。
说白了 Predicate 就是为了实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理,接下来我们接下 Spring Cloud GateWay 内置几种 Predicate 的使用。
微服务架构实践(API GateWay)
在微服务架构风格中,一个大应用通常会被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 Rest Api 风格的接口来被 H5, Android, IOS 以及第三方应用程序调用。
我们通常需要在一个界面上展示很多数据,这些数据可能来自于不同的微服务中,比如在一个电商系统中,查看一个商品详情页,这个商品详情页包含商品的标题,价格,库存,评论等,这些数据对于后端来说可能是位于不同的微服务系统之中。我们要如何从这些微服务中拉取相应的信息回来呢?
基于以上背景,在微服务架构中,我们可能会遇到一下问题:
服务的划分可能随着时间或者需求变更而变化
服务实例会动态变化
服务的API粒度,相对而言在微服务架构中,每个服务都只提供相对细粒度的API
不同的客户端(H5,App等)可能需要不同的数据
这种情况下,我们就需要:API 网关(API Gateway)。API 网关模式意味着你要把API 网关放到你的微服务们的最前端,并且要让 API 网关变成由应用所发起的每个请求的入口,这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式。
API Gateway 可以分为两种:
1.单节点 API Gateway
2.BFF(Backends for frontends) Gateway
API 网关职责
在我们内部,API 网关需要承担包括但不限于下面的这些职责:
1.请求路由,版本控制
API Gateway 是微服务的入口,可以根据不同的请求路由到不同的服务上,也可以在 Gateway 上进行路由的版本控制,这样即使后服务发生了变化,Gateway 的路径依然可以不改变。
2.用户登录,权限认证
客户端在与我们后端服务进行交互之前,需要先进行登录鉴权操作,这是后端所有的服务都需要有的共有逻辑,因此在 Gateway 做这个事情就再合适不过。
3.数据聚合
由于不同的客户端往往需要的数据完全不同,而这些数据又是不同的 service 提供的,比如上面提到的查看一个商品详情页,我们可能需要同时从商品服务,库存服务,评价服务等中拉取信息,我们可以借助 Gateway 方便完成来自不同 service 的数据聚合。
4.协议转换
在我们的实践中,CS(Client to Server)协议和SS(Server to Server)协议是不一样的,为了保证数据传输的可靠性,我们的CS协议会有鉴权以及加密解密的逻辑,而在内部的SS协议则不需要这些逻辑,因此在 Gateway 我们需要有一个协议转换的过程。
5.熔断,降级,限流
当监测到某个服务发生异常,或者当服务的流量超过我们服务的承载能力等情况时,我们可以采取相应的措施,对整个系统的容错性、稳定性有很大帮助。
6.负载均衡
API 网关知道所有服务实例的地址,所以可以根据不同服务采取不同的负载均衡策略。
7.灰度发布
有时候我不希望让所有的流量都一次性的到达程序的新版本,因为那个新版本也许并没有测试地很充分。灰度发布允许你直接只导入指定量的流量到新的版本,API 网关就可以帮你来做这件事情。你可以配置10%的请求到新的版本,然后一旦你确保了新版本没有bug,你可以把流量切换到100%。
API 网关架构
在我们的内部规划中(部分功能未实现),我们的 API 网关主要会分为三个部分,也就是上图中绿色的几部分:
1.多网关集群(Backends for frontends)
我们针对不同的客户端,都有相应的网关层来接入。现阶段这一部分已经实现的功能主要是:用户登录,鉴权,服务发现注册,协议转换,接口版本控制等。后续我们还规划的功能有:监控,APM调用链,日志,流控策略等。
2.聚合服务(Merge Service)
在某些客户端的需求中,比如上面提到的商品详情的页面,我们需要从多个服务拉取数据,为了减少客户端的复杂度,以及加快客户端的访问速度,我们会在前面加一个聚合层,用来做聚合查询,在某些接口中可以把多个服务的数据一次性返回给客户端。
3.仪表盘管理端(Dashboard)
Dashboard 提供可视化的分析平台,包括服务的管理,监控数据报警配置,日志查询,灰度发布操作,API文档管理等,这些功能对于开发和日常运维来说是非常重要的。
参考资料
由表及里学 ProjectReactor http://blog.yannxia.top/2018/06/26/java/spring/projectreactor/