服务门户:Spring Cloud Gateway 如何把好微服务的大门
服务门户:Spring Cloud Gateway 如何把好微服务的大门
对于用户端从外侧访问微服务如何有效管理,微服务又是如何将接口暴露给用户呢?这就需要通过 API 网关实现需求了,学习三方面知识:
介绍 API 网关的用途与产品;
讲解 Spring Cloud Gateway 的配置技巧;
讲解 Gateway执行原理与自定义过滤器(Filter)。
API 网关的作用
如下图所示,对于整个微服务来说如果将每一个微服务的接口直接暴露给用户是错误的做法,这里主要体现出三个问题:
服务将所有 API 接口对外直接暴露给用户端,这本身就是不安全和不可控的,用户可能越权访问不属于它的功能,例如普通的用户去访问管理员的高级功能。
后台服务可能采用不同的通信方式,如服务 A 采用 RESTful 通信,服务 B 采用 RPC 通信,不同的接入方式让用户端接入困难。尤其是 App 端接入 RPC 过程更为复杂。
在服务访问前很难做到统一的前置处理,如服务访问前需要对用户进行鉴权,这就必须将鉴权代码分散到每个服务模块中,随着服务数量增加代码将难以维护。
为了解决以上问题,API 网关应运而生,加入网关后应用架构变为下图所示;
当引入 API 网关后,在用户端与微服务之间建立了一道屏障,通过 API 网关为微服务访问提供了统一的访问入口,所有用户端的请求被 API 网关拦截并在此基础上可以实现额外功能,例如:
针对所有请求进行统一鉴权、熔断、限流、日志等前置处理,让微服务专注自己的业务。
统一调用风格,通常 API 网关对外提供 RESTful 风格 URL 接口。用户传入请求后,由 API 网关负责转换为后端服务需要的 RESTful、RPC、WebService 等方式,这样便大幅度简化用户的接入难度。
更好的安全性,在通过 API 网关鉴权后,可以控制不同角色用户访问后端服务的权利,实现了服务更细粒度的权限控制。
API 网关是用户端访问 API 的唯一入口,从用户的角度来说只需关注 API 网关暴露哪些接口,至于后端服务的处理细节,用户是不需要知道的。从这方面讲,微服务架构通过引入 API 网关,将用户端与微服务的具体实现进行了解耦
API 网关主流产品
API 网关是微服务架构中必要的组件,具体的实现产品在软件市场上层出不穷,下面我列举三款在国内外主流的开源产品
OpenRestyOpenResty 是一个强大的 Web 应用服务器,Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,更主要的是在性能方面,OpenResty可以快速构造出足以胜任 10K 以上并发连接响应的超高性能 Web 应用系统。360、UPYUN、阿里云、新浪、腾讯网、去哪儿网、酷狗音乐等都是 OpenResty 的深度用户。
OpenResty 因为性能强大在微服务架构早期深得架构师的喜爱。但 OpenResty 是一款独立的产品,与主流的注册中心存在一定兼容问题,需要架构师独立实现其服务注册、发现的功能。后来 Spring Cloud 官方极力推崇自家封装的 Zuul 或者 Spring Cloud Gateway,渐渐 OpenResty 便淡出了我们的视野。但不能否认,OpenResty 仍是一款优秀的 API 网关产品。
Spring Cloud ZuulZuul 是 Netflix 开源的微服务网关,它的主要职责是对用户请求进行路由转发与过滤。早期Spring Cloud 与 Netfilx 合作,使用 Zuul 作为微服务架构的首选网关产品。Zuul 是基于 J2EE Servlet 实现路由转发,网络通信采用同步方式,使用简单部署方便。经过 Spring Cloud 对 Zuul 的封装,Spring Cloud Zuul 应运而生。Spring Cloud Zuul 在原有 Zuul 的基础上,增加对注册中心的支持,同时在基于 Spring Boot Starter 机制基础上,可以在极短的时间内完成 API 网关的开发部署任务。
但好景不长,后来 Netflix 内部产生分歧,Netflix 官方宣布 Zuul 停止维护,这让 Spring 机构也必须转型。于是 Spring Cloud 团队决定开发自己的第二代 API 网关产品:Spring Cloud Gateway。
Spring Cloud Gateway
与 Zuul 是“别人家的孩子”不同,Spring Cloud Gateway 是 Spring 自己开发的新一代 API 网关产品。它基于 NIO 异步处理,摒弃了 Zuul 基于 Servlet 同步通信的设计,因此拥有更好的性能。同时,Spring Cloud Gateway 对配置进行了进一步精简,比 Zuul 更加简单实用。
以下是 Spring Cloud Gateway 的关键特征:
基于 JDK 8+ 开发;
基于 Spring Framework 5 + Project Reactor + Spring Boot 2.0 构建;
支持动态路由,能够匹配任何请求属性上的路由;
支持基于 HTTP 请求的路由匹配(Path、Method、Header、Host 等);
过滤器可以修改 HTTP 请求和 HTTP 响应(增加/修改 Header、增加/修改请求参数、改写请求 Path 等等);
...
当下 Spring Cloud Gateway 已然是 Spring Cloud 体系上API 网关标准组件。Spring Cloud Gateway 十分优秀,Spring Cloud Alibaba 也默认选用该组件作为网关产品,下面我们就通过实例讲解 Spring Cloud Gateway 的使用办法。
当下 Spring Cloud Gateway 已然是 Spring Cloud 体系上API 网关标准组件。Spring Cloud Gateway 十分优秀,Spring Cloud Alibaba 也默认选用该组件作为网关产品,下面我们介绍 Spring Cloud Gateway 的使用办法。
Spring Cloud Gateway的配置技巧
Spring Cloud Gateway使用入门
示例说明:
假设“service-a”微服务提供了三个 RESTful 接口。
假设 “service-b” 微服务提供了三个 RESTful 接口。
如何通过部署 Spring Cloud Gateway 实现 API 路由功能来屏蔽后端细节呢?
第一步,利用 Spring Initializr 向导创建 Gateway 工程,确保 pom.xml 引入以下依赖:
<!-- Nacos客户端 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Spring Cloud Gateway Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 对外提供Gateway应用监控指标 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第二步,在 application.yml 增加如下配置。
spring:
application:
name: gateway #配置微服务id
cloud:
nacos:
discovery:
server-addr: 192.168.31.101:8848 #nacos通信地址
username: nacos
password: nacos
gateway: #让gateway通过nacos实现自动路由转发
discovery:
locator:
enabled: true #locator.enabled是自动根据URL规则实现路由转发
server:
port: 80 #服务端口号
management:
endpoints:
web:
exposure:
include: '*' #对外暴露actuator所有监控指标,便于监控系统收集跟踪
在上面的配置中最重要的一句是:
spring.cloud.gateway.discovery.locator.enabled=true
http://网关IP:端口/微服务id/URI
访问后 Gateway 按下图流程进行请求路由转发。
咱们来梳理下路由转发流程:
Gateway、service-a 这些都是微服务实例,在启动时向 Nacos 注册登记;
Gateway 网关实例收到请求,解析其中第二部分 service-a,即微服务 Id,第三部分 URI 为“/list”。之后向 Nacos 查询 service-a 可用实例列表;
Nacos 返回 120 与 121 两个可用微服务实例信息;
Spring Cloud Gateway 内置 Ribbon,根据默认轮询策略将请求转发至 120 实例,转发的完整 URL 将附加用户的 URI,即http://ip:port/list;
120 实例处理后返回 JSON 响应数据给 Gateway;
Gateway 返回给用户端,完成一次完整的请求路由转发过程。
说到这,我们已理解了 Spring Cloud Gateway 的执行过程。但是真实项目中,存在着各种特殊的路由转发规则,而非自动路由能简单解决的,在 Spring Cloud Gateway 项目中内置了强大的“谓词”系统,可以满足企业应用中的各种转发规则要求,下面介绍常见的谓词用法。
谓词(Predicate)与过滤器(Filter)
在讲解前需要引入 Gateway 网关三个关键名词:路由(Route)、谓词(Predicate)、过滤器(Filter)。
谓词(Predicate)
这里我们给出一个实例,将原有 Gateway 工程的 application.yml 文件修改为下面的设置:
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 192.168.31.10:8848
username: nacos
password: nacos
gateway:
discovery:
locator:
enabled: false #不再需要Gateway路由转发
routes: #路由规则配置
#第一个路由配置,service-a路由规则
- id: service_a_route #路由唯一标识
#lb开头代表基于gateway的负载均衡策略选择实例
uri: lb://service-a
#谓词配置
predicates:
#Path路径谓词,代表用户端URI如果以/a开头便会转发到service-a实例
- Path=/a/**
#After生效时间谓词,2020年10月15日后该路由才能在网关对外暴露
- After=2020-10-05T00:00:00.000+08:00[Asia/Shanghai]
#谓词配置
filters:
#忽略掉第一层前缀进行转发
- StripPrefix=1
#为响应头附加X-Response=Blue
- AddResponseHeader=X-Response,Blue
#第二个路由配置,service-b路由规则
- id: service_b_route
uri: lb://service-b
predicates:
- Path=/b/**
filters:
- StripPrefix=1
server:
port: 80
management:
endpoints:
web:
exposure:
include: '*'
完整的路由配置格式固定如下:
spring:
gateway:
discovery:
locator:
enabled: false #不再需要Gateway路由转发
routes:
- id: xxx #路由规则id
uri: lb://微服务id #路由转发至哪个微服务
predicates:
//具体的谓词
filters:
//具体的过滤器
其中 predicates 是重点,说明路由生效条件,在这里我将常见的谓词使用形式列出来。
After 代表在指定时点后路由规则生效。
predicates:
- After=2020-10-04T00:00:00.000+08:00
Before 代表在指定时点前路由规则生效。
predicates:
- Before=2020-01-20T17:42:47.789-07:00[America/Denver]
Path 代表 URI 符合映射规则时生效。
predicates:
- Path=/b/**
Header 代表包含指定请求头时生效。
predicates:
- Header=X-Request-Id, \d+
这里额外解释下,如果请求具有名为 X-Request-Id 的 Header,其值与\d+正则表达式匹配(具有一个或多个数字的值),则该路由匹配。
Method 代表要求 HTTP 方法符合规定时生效。
predicates:
- Method=GET
谓词是 Gateway 网关中最灵活的部分,刚才列举的是最常用的谓词,还有很多谓词是在文中没有提到,如果你对这部分感兴趣可以翻阅https://spring.io/projects/spring-cloud-gateway进行学习。
今天就这末多,东西比较多,明天接着来