微服务的接口都是直接对外暴露的,可以直接通过外部访问,为了保证对外服务的安全性服务端实现的微服务接口通常都带有一定的权限校验机制,由于使用了微服务,原本一个应用的的多个模块拆分成了多个应用,我们不得不实现多次校验逻辑,当这套逻辑需要修改时,我们需要修改多个应用,加重了开发人员的负担。
针对以上问题,一个常用的解决方案就是使用API网关
1. 什么是API网关
API网关(简称网关) 也是一个服务,通常是后端服务的唯一入口.它的定义类似设计模式中的Facade模式(门面模式,也称外观模式).它就类似整个微服务架构的门面,所有的外部客户端访问,都需要经过它来进行调度和过滤.
网关的核心功能
- 权限控制: 作为微服务的入口,对用户进行权限校验,如果校验失败则进行拦截
- 动态路由:一切请求先经过网关,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务
- 负载均衡: 当路由的目标服务有多个时,还需要做负载均衡
- 限流: 请求流量过高时,按照网关中配置微服务能够接受的流量进行放行,避免服务压力过大
类似前台的⼯作
- 权限控制: ⾝份验证
- 动态路由: 根据外来客⼾的需求, 把客⼾带到指定的部⻔去处理
- 负载均衡: ⼀个部⻔有很多⼈时, 前台会帮客⼾选择具体某个⼈处理
- 限流: 公司到访客⼾较多时, 进⾏流量限制, ⽐如告知明天再来
2. 常见的网关实现
业界常⽤的⽹关⽅式有很多, 技术⽅案也较成熟, 其中不乏很多开源产品, ⽐如Nginx, Kong, Zuul,
Spring Cloud Gateway等. 下⾯介绍两种常⻅的⽹关⽅案.
Zuul
Zuul 是 Netflix 公司开源的一个API网关组件,是Spring Cloud Netflix 子项目的核心组件之它可以和 Eureka、Ribbon、Hystrix等组件配合使用.在Spring Cloud Finchley正式版之前, Spring Cloud推荐的网关是Netflix提供的Zuul(此处指Zuul 1.X)然而Netflix在2018年宣布一部分组件进入维护状态,不再进行新特性的开发,这部分组件中就包含Zuul.
Spring Cloud Gateway
Spring Cloud Gateway是Spring Cloud的一个全新的API网关项目,基于Spring+SpringBoot等技术开发,目的是为了替换掉Zuu!.旨在为微服务架构提供一种简单而有效的途径来转发请求,并为他们提供横切关注点,比如: 安全性,监控/指标和弹性。
在性能方面,根据官方提供的测试报告,Spring Cloud Gateway的RPS(每秒请求数)是Zuul的1.6倍.测试报告参考: https://github.com/spencergibb/spring-cloud-gateway-bench
3. Spring cloud gateway
3.1 快速上手
3.1.1 创建网关项目
API⽹关也是⼀个服务.
3.1.2 引入依赖
bash
<!--⽹关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--基于nacos实现服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
3.1.3 编写启动类
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class , args);
}
}
3.1.4 添加Gateway的路由配置
bash
server:
port: 10030 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
discovery:
server-addr: nacosIp:端口
gateway:
routes: # 网关路由配置
- id: product-service # 路由ID, 自定义, 唯一即可
uri: lb://product-service # 目标服务地址
predicates: # 路由条件
- Path=/product/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**
3.1.5 测试
启动网关服务。
1. 通过网关服务访问product-service,http://127.0.0.1:10040/product/1001
url符合yml文件中配置的 /product/**规则,路由转发到product-service: http://product-service/product/1001
通过网关服务的日志,可以观察到,网关服务从Nacos获取服务列表
bash
2024-09-12T17:32:13.372+08:00 INFO 3356 --- [t.remote.worker] com.alibaba.nacos.common.remote.client : [9f9c4461-ebf3-41cd-b9ee-17605253a90b] Notify connected event to listeners.
2024-09-12T17:32:13.372+08:00 INFO 3356 --- [t.remote.worker] com.alibaba.nacos.client.naming : Grpc connection connect
2024-09-12T17:32:13.372+08:00 INFO 3356 --- [ main] com.alibaba.nacos.common.remote.client : [9f9c4461-ebf3-41cd-b9ee-17605253a90b] Register server push request handler:com.alibaba.nacos.common.remote.client.RpcClient$ConnectResetRequestHandler
2024-09-12T17:32:13.374+08:00 INFO 3356 --- [ main] com.alibaba.nacos.common.remote.client : [9f9c4461-ebf3-41cd-b9ee-17605253a90b] Register server push request handler:com.alibaba.nacos.common.remote.client.RpcClient$$Lambda$845/0x000002623b5a34f8
2024-09-12T17:32:13.376+08:00 INFO 3356 --- [ main] com.alibaba.nacos.client.naming : [REGISTER-SERVICE] fcc2c221-085b-4864-bff4-f1f18f734cb0 registering service gateway with instance Instance{instanceId='null', ip='192.168.5.1', port=10040, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='DEFAULT', serviceName='null', metadata={IPv6=[2001:0:2851:b9f0:24d7:f521:fe3d:44e3], preserved.register.source=SPRING_CLOUD}}
2024-09-12T17:32:13.421+08:00 INFO 3356 --- [ main] c.a.c.n.registry.NacosServiceRegistry : nacos registry, DEFAULT_GROUP gateway 192.168.5.1:10040 register finished
2024-09-12T17:32:13.498+08:00 INFO 3356 --- [ main] com.guan.gateway.GatewayApplication : Started GatewayApplication in 8.144 seconds (process running for 9.467)
2024-09-12T17:41:02.993+08:00 INFO 3356 --- [oundedElastic-1] com.alibaba.nacos.client.naming : [SUBSCRIBE-SERVICE] service:product-service, group:DEFAULT_GROUP, clusters:
2024-09-12T17:41:03.079+08:00 INFO 3356 --- [oundedElastic-1] com.alibaba.nacos.client.naming : init new ips(1) service: DEFAULT_GROUP@@product-service -> [{"instanceId":"192.168.5.1#9090#BJ#DEFAULT_GROUP@@product-service","ip":"192.168.5.1","port":9090,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"BJ","serviceName":"DEFAULT_GROUP@@product-service","metadata":{"preserved.register.source":"SPRING_CLOUD","IPv6":"[2001:0:2851:b9f0:24ce:ef45:fe3d:44e3]"},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000}]
2024-09-12T17:41:03.090+08:00 INFO 3356 --- [oundedElastic-1] com.alibaba.nacos.client.naming : current ips:(1) service: DEFAULT_GROUP@@product-service -> [{"instanceId":"192.168.5.1#9090#BJ#DEFAULT_GROUP@@product-service","ip":"192.168.5.1","port":9090,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"BJ","serviceName":"DEFAULT_GROUP@@product-service","metadata":{"preserved.register.source":"SPRING_CLOUD","IPv6":"[2001:0:2851:b9f0:24ce:ef45:fe3d:44e3]"},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000}]
2024-09-12T17:41:03.615+08:00 INFO 3356 --- [.42.168.168-161] com.alibaba.nacos.common.remote.client : [9f9c4461-ebf3-41cd-b9ee-17605253a90b] Receive server push request, request = NotifySubscriberRequest, requestId = 3
2024-09-12T17:41:03.616+08:00 INFO 3356 --- [.42.168.168-161] com.alibaba.nacos.common.remote.client : [9f9c4461-ebf3-41cd-b9ee-17605253a90b] Ack server push request, request = NotifySubscriberRequest, requestId = 3
2. 通过网关访问order-service
http://127.0.0.1:10040/order/1
url符合yml文件中配置的 /order/**规则,路由转发到product-service: http://product-order/product/1