第8章:API网关设计¶
8.1 API网关概述¶
什么是API网关¶
API网关是系统的统一入口,负责路由请求、认证授权、限流熔断、监控日志等功能。
API网关的作用¶
- 统一入口:所有请求通过网关进入
- 路由转发:根据规则路由到不同服务
- 认证授权:统一处理认证和授权
- 限流熔断:保护后端服务
- 监控日志:统一监控和日志收集
API网关的优势¶
- 简化客户端:客户端只需知道网关地址
- 统一管理:集中管理路由、认证等
- 安全性:统一的安全策略
- 可观测性:统一的监控和日志
8.2 网关功能¶
8.2.1 路由转发¶
Python
from fastapi import FastAPI, Request
import httpx
app = FastAPI()
# 路由规则
routes = {
"/api/users": "http://user-service",
"/api/orders": "http://order-service",
"/api/products": "http://product-service"
}
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def proxy(request: Request, path: str):
# 匹配路由
for route, target in routes.items():
# 去掉路由前缀的 / 后与请求路径比较
route_prefix = route.lstrip("/")
if path.startswith(route_prefix):
# 转发请求(去掉前缀后拼接目标地址)
sub_path = path[len(route_prefix):]
url = f"{target}{sub_path}"
async with httpx.AsyncClient() as client:
response = await client.request(
method=request.method,
url=url,
headers=dict(request.headers),
content=await request.body()
)
return response.json()
return {"error": "Route not found"}
8.2.2 认证授权¶
Python
from fastapi import FastAPI, Request, HTTPException, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
security = HTTPBearer()
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
token = credentials.credentials
# 验证token
user = validate_token(token)
if not user:
raise HTTPException(status_code=401, detail="Invalid token")
return user
@app.get("/api/users/{user_id}")
async def get_user(user_id: int, user: dict = Depends(verify_token)):
# 调用用户服务
async with httpx.AsyncClient() as client:
response = await client.get(f"http://user-service/users/{user_id}")
return response.json()
def validate_token(token: str):
# 验证JWT token
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
return payload
except jwt.InvalidTokenError:
return None
8.2.3 限流熔断¶
Python
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.get("/api/users/{user_id}")
@limiter.limit("100/minute")
async def get_user(request: Request, user_id: int):
# 调用用户服务
async with httpx.AsyncClient() as client:
response = await client.get(f"http://user-service/users/{user_id}")
return response.json()
8.2.4 监控日志¶
Python
import logging
import time
from prometheus_client import Counter, Histogram # Counter计数器:统计元素出现次数
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Prometheus指标
request_count = Counter('gateway_requests_total', 'Total requests', ['method', 'endpoint'])
request_duration = Histogram('gateway_request_duration_seconds', 'Request duration')
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def proxy(request: Request, path: str):
start_time = time.time()
# 记录请求
logger.info(f"{request.method} {request.url}")
try: # try/except捕获异常
# 转发请求
response = await forward_request(request, path)
# 记录成功
request_count.labels(method=request.method, endpoint=path).inc()
return response
except Exception as e:
# 记录错误
logger.error(f"Error: {e}")
raise
finally:
# 记录耗时
duration = time.time() - start_time
request_duration.observe(duration)
8.3 主流API网关¶
8.3.1 Nginx¶
Nginx Configuration File
upstream user_service {
server user-service1:8001;
server user-service2:8001;
}
upstream order_service {
server order-service1:8002;
server order-service2:8002;
}
server {
listen 80;
# 路由到用户服务
location /api/users/ {
proxy_pass http://user_service/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 路由到订单服务
location /api/orders/ {
proxy_pass http://order_service/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 限流
# 注意:limit_req_zone 指令必须放在 http{} 块中,不能放在 server{} 块内
# 即:limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; 应移到 http{} 级别
limit_req zone=api burst=20 nodelay;
}
8.3.2 Kong¶
Bash
# 安装Kong
docker run -d --name kong \
--network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_USER=kong" \
-e "KONG_PG_PASSWORD=kong" \
-p 8000:8000 \
-p 8443:8443 \
kong:latest
# 添加服务
curl -X POST http://localhost:8001/services \
--data name=user-service \
--data url=http://user-service:8001
# 添加路由
curl -X POST http://localhost:8001/services/user-service/routes \
--data paths[]=/api/users
# 添加限流插件
curl -X POST http://localhost:8001/services/user-service/plugins \
--data name=rate-limiting \
--data config.minute=100 \
--data config.policy=local
8.3.3 Spring Cloud Gateway¶
Java
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service", r -> r
.path("/api/users/**")
.filters(f -> f
.stripPrefix(2)
.requestRateLimiter()
.configure(c -> c
.setRateLimiter(redisRateLimiter())
.setKeyResolver(userKeyResolver())
)
)
.uri("lb://user-service"))
.route("order-service", r -> r
.path("/api/orders/**")
.filters(f -> f.stripPrefix(2))
.uri("lb://order-service"))
.build();
}
@Bean
public RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(10, 20, 1);
}
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
8.3.4 APISIX¶
YAML
# apisix配置
routes:
- uri: /api/users/*
upstream:
type: roundrobin
nodes:
"user-service1:8001": 1
"user-service2:8001": 1
plugins:
limit-req:
burst: 20
key_type: var
key: "remote_addr"
rejected_code: 429
rate: 10
jwt-auth:
key: app-key
- uri: /api/orders/*
upstream:
type: roundrobin
nodes:
"order-service1:8002": 1
"order-service2:8002": 1
8.4 网关设计模式¶
8.4.1 单网关模式¶
所有请求通过一个网关。
优点: - 架构简单 - 易于管理
缺点: - 单点故障 - 性能瓶颈
8.4.2 多网关模式¶
不同类型的请求使用不同的网关。
优点: - 性能更好 - 故障隔离
缺点: - 架构复杂 - 管理成本高
8.4.3 边缘网关模式¶
在边缘部署网关,就近处理请求。
优点: - 延迟低 - 性能好
缺点: - 部署复杂 - 一致性难保证
8.5 网关性能优化¶
8.5.1 连接池优化¶
Python
import httpx
# 配置连接池
client = httpx.AsyncClient(
limits=httpx.Limits(
max_connections=1000,
max_keepalive_connections=100
),
timeout=httpx.Timeout(30.0)
)
8.5.2 缓存优化¶
Python
from fastapi_cache import FastAPICache, Coder
from fastapi_cache.backends.redis import RedisBackend
# 配置缓存
FastAPICache.init(RedisBackend(redis_client), prefix="fastapi-cache")
@app.get("/api/users/{user_id}")
@cache(expire=60) # 缓存60秒
async def get_user(user_id: int):
# 调用用户服务
response = await client.get(f"http://user-service/users/{user_id}")
return response.json()
8.5.3 压缩优化¶
Python
from fastapi import Response
@app.get("/api/users/{user_id}")
async def get_user(user_id: int): # async def定义异步函数;用await调用
# 调用用户服务
response = await client.get(f"http://user-service/users/{user_id}") # await等待异步操作完成
# 返回压缩响应
import gzip
compressed = gzip.compress(response.content)
return Response(
content=compressed,
media_type="application/json",
headers={"Content-Encoding": "gzip"}
)
8.6 实战练习¶
练习1:实现一个简单的API网关¶
实现一个API网关,包括: 1. 路由转发 2. 认证授权 3. 限流熔断 4. 监控日志
练习2:设计一个多网关架构¶
设计一个多网关架构: 1. 内部网关 2. 外部网关 3. 管理网关
练习3:优化网关性能¶
优化网关性能: 1. 连接池优化 2. 缓存优化 3. 压缩优化
8.7 面试准备¶
常见面试题¶
- 什么是API网关?它有什么作用?
- API网关有哪些功能?
- 如何设计一个API网关?
- API网关的性能如何优化?
- 主流的API网关有哪些?
项目经验准备¶
准备一个API网关项目: - 使用的网关方案 - 遇到的挑战 - 解决方案 - 项目成果
8.8 总结¶
本章介绍了API网关设计,包括网关功能、主流API网关和性能优化。API网关是微服务架构的重要组成部分。
关键要点¶
- API网关是系统的统一入口
- 网关功能包括路由转发、认证授权、限流熔断、监控日志
- 主流API网关包括Nginx、Kong、Spring Cloud Gateway、APISIX
- 网关设计模式包括单网关、多网关、边缘网关
- 网关性能优化包括连接池、缓存、压缩
下一步¶
下一章将深入学习搜索架构,包括Elasticsearch、索引设计等内容。