了解微服务中的 API 网关模式:简单指南
从单个整体应用程序过渡到微服务架构可以解决许多问题。它允许团队独立工作、单独部署服务并根据需要扩展系统的各个部分。然而,它也带来了一个新的挑战:客户如何与所有这些独立服务交互?
如果您有十个、五十个或数百个微型微服务,移动应用程序或网页是否应该直接连接到其中的每一个?
这就是 API 网关模式 的用武之地。在本指南中,我们将通过简单的文字和现实世界的类比来详细介绍 API 网关是什么、为什么需要它以及它如何简化您的微服务系统。
现实世界的类比:酒店接待员
想象一下您正在入住一家大型豪华度假酒店。度假村有许多不同的部门:
- 客房服务(干净的床单)
- 客房服务(食物)
- 礼宾部(预订旅游)
- 账单(用于支付账单)
如果您想要一条干净的毛巾,您不必穿过度假村试图找到客房服务大楼。如果你想吃晚饭,就不要敲厨房的门。相反,您可以致电前台接待员。
接待员听取您的请求,确定哪个部门可以解决,并为您联系或处理。
在这种情况下:
- 您 是客户端(移动应用程序或浏览器)。
- 接待员是API网关。
- 部门(客房服务、客房服务、计费)是微服务。
问题:客户端到服务的直接通信
在了解网关如何工作之前,让我们看看如果我们“不”使用网关会发生什么。
假设您的电子商务应用程序具有三个独立的微服务:
- 用户服务(管理个人资料)
- 产品服务(管理目录)
- 订单服务(管理结账)
如果没有 API 网关,客户端应用程序必须直接向每个服务的单独地址(IP 或 URL)发送单独的请求:
这种直接连接方法会带来几个主要问题:
- 太多端点:客户端应用程序必须记住三个单独的 URL。如果拆分服务或更改其地址,则必须更新客户端应用程序。
- 安全噩梦:每个微服务必须单独实现身份验证(检查登录令牌)、SSL 证书和防火墙规则。
- 网络开销:客户端可能需要通过慢速移动网络发出三个单独的网络请求才能加载单个页面(例如,获取配置文件、获取产品详细信息和获取订单历史记录)。
- 协议差异:您的客户端应用程序可能更喜欢使用 HTTP/JSON 等标准 Web 协议,但您的内部服务可能使用 gRPC 或 AMQP 等专用协议进行更快的通信。
解决方案:API 网关模式
API 网关 是位于客户端应用程序和内部微服务之间的辅助服务器。它充当所有传入请求的单一入口点。
客户端不再调用三个不同的服务,而是对 API 网关进行一次调用。然后,网关将请求转发到正确的内部服务,收集结果并将其发送回客户端。
API 网关的主要职责
API 网关的作用不仅仅是引导流量。它负责处理“横切关注点”——否则每个微服务都必须为其编写代码的任务:
- 路由:网关获取传入 URL(如
/api/v1/orders)并将其映射到正确的内部服务地址。 - 身份验证和授权:网关在入口处验证安全令牌(如 JWT)。如果请求无效,则会立即拒绝,从而避免微服务在未经身份验证的请求上浪费 CPU 周期。
- 速率限制:它通过限制用户每分钟可以发出的请求数量来防止恶意机器人或有缺陷的客户端向您的系统发送垃圾邮件。
- 负载均衡:网关可以在微服务的多个实例之间均匀分配传入流量,以防止任何单个服务器过载。
- 协议翻译:它可以将面向用户的 JSON 请求转换为高性能的内部 gRPC 消息,允许服务以其首选语言相互通信。
一个简单的实现:代码示例
为了了解路由变得多么容易,让我们看一下设置 API 网关的两种常见方法。
1.声明式路由(Spring Cloud Gateway YAML)
在企业 Java 系统中,您经常使用简单的配置文件来配置路由。网关根据以下规则自动转发请求:
spring:
cloud:
gateway:
routes:
- id: user_service_route
uri: http://internal-user-service:8081
predicates:
- Path=/api/users/**
- id: product_service_route
uri: http://internal-product-service:8082
predicates:
- Path=/api/products/**
2. 编程式路由(Node.js 网关模型)
如果你想使用 Express 在 Javascript 中构建一个轻量级 API 网关,它看起来像这样:
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
const PORT = 3000;
// 1. Simple Security/Authentication Check at the door
const authenticate = (req, res, next) => {
const token = req.headers['authorization'];
if (token === 'secret-handshake-token') {
next(); // Token is valid, proceed
} else {
res.status(401).json({ error: 'Unauthorized Access!' });
}
};
// Apply auth check to all incoming gateway requests
app.use(authenticate);
// 2. Route requests to correct internal microservices
app.use('/api/users', createProxyMiddleware({ target: 'http://localhost:8081', changeOrigin: true }));
app.use('/api/products', createProxyMiddleware({ target: 'http://localhost:8082', changeOrigin: true }));
app.use('/api/orders', createProxyMiddleware({ target: 'http://localhost:8083', changeOrigin: true }));
app.listen(PORT, () => {
console.log(`API Gateway running smoothly on port ${PORT}`);
});
API 网关模式的优缺点
与任何架构决策一样,使用 API 网关也需要权衡:
| 优势(专业版) | 缺点(缺点) |
|---|---|
| 简单的客户端界面:客户端只需要知道一个域名。 | 单点故障:如果网关出现故障,整个应用程序将无法访问。 |
| 集中安全性:在一处实施登录检查、SSL 和 CORS。 | 额外延迟:请求需要稍长的时间,因为它们必须经过额外的网络跃点。 |
| 减少代码重复:避免在每个服务中重写身份验证和速率限制代码。 | 维护开销:每当添加、删除或拆分服务时,都必须更新网关。 |
## 结论
API 网关模式是现代微服务架构的基石。通过充当单一智能入口点,它使客户端应用程序免受内部服务设置复杂性的影响。它简化了客户端代码,集中了安全性,并有效地处理流量管理。
虽然它引入了较小的网络跃点,并且需要在生产中设置高可用性,但更干净、更安全和可管理的代码库的好处使其成为任何不断增长的分布式系统的强烈推荐模式。