跳转至

第8章:API网关设计

API网关设计

8.1 API网关概述

什么是API网关

API网关是系统的统一入口,负责路由请求、认证授权、限流熔断、监控日志等功能。

API网关的作用

  1. 统一入口:所有请求通过网关进入
  2. 路由转发:根据规则路由到不同服务
  3. 认证授权:统一处理认证和授权
  4. 限流熔断:保护后端服务
  5. 监控日志:统一监控和日志收集

API网关的优势

  1. 简化客户端:客户端只需知道网关地址
  2. 统一管理:集中管理路由、认证等
  3. 安全性:统一的安全策略
  4. 可观测性:统一的监控和日志

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 单网关模式

所有请求通过一个网关。

优点: - 架构简单 - 易于管理

缺点: - 单点故障 - 性能瓶颈

Text Only
客户端 -> 网关 -> 微服务

8.4.2 多网关模式

不同类型的请求使用不同的网关。

优点: - 性能更好 - 故障隔离

缺点: - 架构复杂 - 管理成本高

Text Only
客户端 -> 内部网关 -> 内部服务
       -> 外部网关 -> 外部服务

8.4.3 边缘网关模式

在边缘部署网关,就近处理请求。

优点: - 延迟低 - 性能好

缺点: - 部署复杂 - 一致性难保证

Text Only
客户端 -> 边缘网关1 -> 微服务
       -> 边缘网关2 -> 微服务

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 面试准备

常见面试题

  1. 什么是API网关?它有什么作用?
  2. API网关有哪些功能?
  3. 如何设计一个API网关?
  4. API网关的性能如何优化?
  5. 主流的API网关有哪些?

项目经验准备

准备一个API网关项目: - 使用的网关方案 - 遇到的挑战 - 解决方案 - 项目成果

8.8 总结

本章介绍了API网关设计,包括网关功能、主流API网关和性能优化。API网关是微服务架构的重要组成部分。

关键要点

  1. API网关是系统的统一入口
  2. 网关功能包括路由转发、认证授权、限流熔断、监控日志
  3. 主流API网关包括Nginx、Kong、Spring Cloud Gateway、APISIX
  4. 网关设计模式包括单网关、多网关、边缘网关
  5. 网关性能优化包括连接池、缓存、压缩

下一步

下一章将深入学习搜索架构,包括Elasticsearch、索引设计等内容。