Spring Cloud (七):API 网关
在微服务架构中,不同服务有不同的地址,客户端需要和多个服务交互,这会带来一些问题
- 客户端需要多次请求不同的微服务,增加复杂性
- 存在跨域请求
- 每个微服务都有独立认证
- 微服务重构时,客户端也要跟着改
API 网关就是客户端和服务端的中间层,所有请求都会先经过 API 网关,再由 API 网关发给后端的微服务
使用了 API 网关后可以做统一的登录、认证、监控、日志、限流、负载均衡、转发,简化了前后端的交互和开发
API 网关有 nginx,kong,zuul,Spring Cloud Gateway,F5 等
zuul
zuul 是 Netflix 开源的微服务网关组件,它可以和 Eureka、Robbin、Hystrix 等组件配合使用
zuul 的功能
- 认证和安全
- 预警和监控
- 动态路由
- 压力测试
- 负载均衡
- 静态处理
- 多区域弹性
启动 zuul 的代码如下
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
@SpringBootApplication
@EnableZuulProxy
public class ZuulServerApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulServerApplication.class, args);
}
}
server:
port: 9000
zuul:
prefix: /api # 访问网关路径的前缀
routes:
service-01: # 服务的名字,可以是任意名字,不会出现在 zuul 的 url 中
path: /product-service/** # 将服务的这个 path,映射到下面的 URL,或是 service id (如果使用了 Consul 或 Eureka)
url: http://localhost:8501 # 比如 zuul-host:zuul-port/api/product-service/product/1 会被映射成 http://localhost:8501/product/1
# service-id: consul-service-1
service-02:
path: /hello-service/**
url: http://localhost:8505
# service-id: consul-service-1
retryable: true
访问 http://localhost:9000/api/product-service/product/1
实际上会被转发到 http://localhost:8501/product/1
Spring Cloud Gateway
zuul 有版本 1 和版本 2,spring cloud 集成的是版本 1,后续可能不会再改,而是推出 Spring Cloud Gateway
Spring Cloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty
Spring Cloud Gateway 的特性 (https://github.com/spring-cloud/spring-cloud-gateway)
- 基于Spring 5, Spring Boot 2 and Project Reactor
- 动态路由
- 基于 HTTP 请求的任意属性(Path, Method, Header, Host, etc…)做路由匹配
- Filters 作用于匹配路由
- Filters 可以修改 HTTP 请求和响应
- 支持 Spring Cloud DiscoveryClient
- 支持负载均衡、限流熔断等功能
spring cloud gateway 的匹配机制比较强大,启动 spring cloud gateway 的代码如下
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
注意需要移除 spring-boot-starter-web,并且如果有一些 dependency 间接依赖 spring-boot-starter-web,那么需要通过 exclude 排除掉,不然会报错:Consider defining a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' in your configuration.
如果用到了 hystrix 的容错功能,那么还要把 hystrix 的依赖添加上
@SpringBootApplication
public class SpringCloudGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudGatewayApplication.class, args);
}
}
server:
port: 9000
spring:
cloud:
gateway:
routes:
- id: service-01 ## 每个路由的 id,任意名字,不会出现在 url 中
uri: http://localhost:8501 ## 和这个路由匹配的请求都转发到 http://localhost:8501
order: 0 ## 优先级,一个请求有可能和多个路由匹配,会执行高优先级的路由
predicates: ## 谓词,满足下面列举的条件的请求,就和这个路由匹配上
- Path=/product-service/** ## 匹配 url 为 /product-service/** 的请求
## 即 gateway-host:gateway-port/product-service/** 会被转发到 http://localhost:8501/**
filters: ## 过滤,对请求做一些处理(下面这里是两个过滤器)
- StripPrefix=1 ## 第一个过滤器:截断路径中的第一个字段,比如 /test/abc 变成 /abc
- name: Hystrix ## 第二个过滤器:通过 Hystrix 做熔断
args:
name: fallbackCmdA
fallbackUri: forward:/fallbackA ## 将 forward 服务的 fallbackA 路径的输出作为熔断的返回
hystrix:
command:
fallbackCmdA:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
也可以通过代码实现这些配置功能
spring cloud gateway 的配置功能很强,下面再举一些例子
# 请求中包含 id 参数的即可匹配路由,比如
# localhost:9000?id=2
predicates:
- Query=id
# 请求中包含 id 参数,且 id 参数以 abc 开头的即可匹配路由,比如
# localhost:9000?id=abc123
# 注意这里的 abc. 是正则表达式
predicates:
- Query=id, abc.
# 请求的 header 中包含 X-Request-Id 参数,且参数的值是数字,即可匹配路由,比如
# curl -H "X-Request-Id:88" localhost:9000
predicates:
- Header=X-Request-Id, \d+
# 请求的 cookie 中包含 sessionId,且值为 test,即可匹配路由,比如
# curl --cookie "sessionId=test" localhost:9000
predicates:
- Cookie=sessionId, test
# GET 请求即可匹配路由
predicates:
- Method=GET
# 请求的路径满足要求,即可匹配路由,比如
# curl localhost:9000/foo/1
# curl localhost:9000/foo/test
predicates:
- Path=/foo/{segment}
# 请求的远程地址满足要求即可匹配路由
predicates:
- RemoteAddr=192.168.1.1/24
# 可以组合使用
predicates:
- Path=/product-service
- Method=GET
- Query=id
Spring Cloud Gateway 的功能配置比 zuul 要多
nginx
nginx 的作用
- 负载均衡
- 地址映射和端口映射
- 静态文件支持、伪静态
- 缓存静态和伪静态页面
- 缓冲请求和响应
- 高可用性,高并发抗压能力,都比较强
- 访问控制、限速等功能
安装 Nginx
sudo apt-get install nginx
Nginx 配置
/etc/nginx/nginx.conf
这个配置文件会引入下面两个目录的配置文件
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
创建 /etc/nginx/conf.d/test.conf (配置文件可以有多个)
server {
listen 80;
server_name localhost;
# location 的 URL 匹配语法
# ~* 表示正则表达式,不区分大小写
# ~ 表示正则表达式,要区分大小写
# = 表示精确匹配
# 没有修饰符的,以指定模式开始,比如 location / 匹配所有以 / 开始的 URL
# 静态页面,直接读取 html 文件
location ~* .*\.html$ {
gzip on;
root /usr/share/nginx/html;
}
# 动态页面,转发给后端
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Nginx 性能强,稳定性高,适合作为全局的网关,但有的功能不具备,比如熔断等
kong
kong 是一个基于 nginx 的,用 nginx_lua 模块编写扩展插件的网关
kong 可以使用 Cassandra/PostgreSQL 数据库来存储数据
https://docs.konghq.com/install/ubuntu/
$ sudo apt-get update
$ sudo apt-get install -y apt-transport-https curl lsb-core
$ echo "deb https://kong.bintray.com/kong-deb `lsb_release -sc` main" | sudo tee -a /etc/apt/sources.list
$ curl -o bintray.key https://bintray.com/user/downloadSubjectPublicKey?username=bintray
$ sudo apt-key add bintray.key
$ sudo apt-get update
$ sudo apt-get install -y kong
配置文件
cp /etc/kong/kong.conf.default /etc/kong/kong.conf
如果配置数据库
CREATE USER kong;
CREATE DATABASE kong OWNER kong;
kong migrations bootstrap [-c /etc/kong/kong.conf]
如果不配置数据库
## 会在当前路径生成 kong.yml
kong config init
## 在 kong.conf 文件里把数据库选项关掉
database = off
declarative_config = /path/to/kong.yml
启动 kong
kong start [-c /etc/kong/kong.conf] [--nginx-conf /path/to/custom_nginx.template]
kong 默认监听以下端口
- 8000:监听客户端的 HTTP 请求,转发到后端服务
- 8443:监听客户端的 HTTPS 请求,转发到后端服务,可以 disable
- 8001:监听 Admin API HTTP 请求,用于配置 Kong
- 8444:监听 Admin API HTTPS 请求,用于配置 Kong
可以通过向 8001 端口发送 POST 请求进行配置
重载 kong
kong reload
停止 kong
kong stop
kong 可以通过 --nginx-conf 指定 nginx 配置
F5
F5 是直接通过硬件实现,和系统及应用无关,只从网络层判断处理,性能强,缺点是成本高,配置可能比其他的复杂
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界