API网关技术 string;

API 网关是微服务架构中的关键组件,用于统一管理API请求、路由、认证授权、速率限制、负载均衡等跨领域功能。本技能涵盖使用Kong、NGINX和AWS API Gateway实现API网关的模式、配置、部署和最佳实践,包括Docker设置、插件管理、安全监控和高可用性设计,适用于后端开发、DevOps和系统架构师,关键词:API网关、微服务、Kong、NGINX、AWS API Gateway、路由策略、认证限流、高可用部署。

DevOps 0 次安装 0 次浏览 更新于 3/5/2026

API 网关

概述

关于使用 Kong、NGINX 和 AWS API Gateway 实现微服务的 API 网关模式的全面指南。

目录

  1. API 网关概念
  2. Kong 设置与配置
  3. NGINX 作为 API 网关
  4. 功能
  5. 路由策略
  6. 安全
  7. 监控
  8. 高可用性
  9. 生产部署
  10. 最佳实践

API 网关概念

核心概念

## API 网关核心概念

### 什么是 API 网关?
- 所有客户端请求的单一入口点
- 将请求路由到适当的微服务
- 处理跨领域关注点

### 关键职责
- 请求路由
- 认证与授权
- 速率限制
- 负载均衡
- 请求/响应转换
- 缓存
- 日志与监控

### 优势
- 简化客户端架构
- 集中化跨领域关注点
- 提供统一的 API 接口
- 支持服务版本控制
- 提升安全态势

网关架构

// gateway-architecture.ts
export interface GatewayConfig {
  name: string;
  routes: Route[];
  services: Service[];
  plugins: Plugin[];
  upstreams: Upstream[];
}

export interface Route {
  name: string;
  paths: string[];
  methods: string[];
  service: string;
  plugins?: string[];
}

export interface Service {
  name: string;
  url: string;
  retries?: number;
  connect_timeout?: number;
  write_timeout?: number;
  read_timeout?: number;
}

export interface Plugin {
  name: string;
  config: Record<string, any>;
}

export interface Upstream {
  name: string;
  targets: Target[];
  algorithm: 'round-robin' | 'least-connections' | 'ip-hash';
  healthchecks?: HealthCheck;
}

export interface Target {
  target: string; // host:port
  weight: number;
}

export interface HealthCheck {
  active: {
    type: 'http' | 'https' | 'tcp';
    http_path: string;
    healthy: { interval: number; successes: number };
    unhealthy: { interval: number; http_failures: number };
  };
}

Kong 设置与配置

Docker 设置

# docker-compose.yml
version: '3.8'

services:
  kong:
    image: kong/kong-gateway:3.4
    ports:
      - "8000:8000"   # HTTP
      - "8443:8443"   # HTTPS
      - "8001:8001"   # Admin API
    environment:
      KONG_DATABASE: "off"
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stdout
      KONG_ADMIN_ERROR_LOG: /dev/stdout
      KONG_ADMIN_LISTEN: "0.0.0.0:8001"
    networks:
      - kong-net

  konga:
    image: pantsel/konga
    ports:
      - "1337:1337"
    environment:
      NODE_ENV: production
    networks:
      - kong-net

networks:
  kong-net:
    driver: bridge

服务配置

// kong-service.ts
import axios from 'axios';

export class KongServiceManager {
  private adminUrl: string;
  
  constructor(adminUrl: string = 'http://localhost:8001') {
    this.adminUrl = adminUrl;
  }
  
  async createService(config: any): Promise<any> {
    const response = await axios.post(`${this.adminUrl}/services`, config);
    return response.data;
  }
  
  async listServices(): Promise<any[]> {
    const response = await axios.get(`${this.adminUrl}/services`);
    return response.data.data;
  }
  
  async getService(serviceId: string): Promise<any> {
    const response = await axios.get(`${this.adminUrl}/services/${serviceId}`);
    return response.data;
  }
  
  async updateService(serviceId: string, config: any): Promise<any> {
    const response = await axios.patch(`${this.adminUrl}/services/${serviceId}`, config);
    return response.data;
  }
  
  async deleteService(serviceId: string): Promise<void> {
    await axios.delete(`${this.adminUrl}/services/${serviceId}`);
  }
}

// 使用
const kong = new KongServiceManager();

// 创建用户服务
await kong.createService({
  name: 'user-service',
  url: 'http://user-service:3000',
  retries: 3,
  connect_timeout: 60000,
  write_timeout: 60000,
  read_timeout: 60000
});

路由配置

// kong-route.ts
export class KongRouteManager {
  private adminUrl: string;
  
  constructor(adminUrl: string = 'http://localhost:8001') {
    this.adminUrl = adminUrl;
  }
  
  async createRoute(serviceId: string, config: any): Promise<any> {
    const response = await axios.post(`${this.adminUrl}/services/${serviceId}/routes`, config);
    return response.data;
  }
  
  async listRoutes(): Promise<any[]> {
    const response = await axios.get(`${this.adminUrl}/routes`);
    return response.data.data;
  }
  
  async updateRoute(routeId: string, config: any): Promise<any> {
    const response = await axios.patch(`${this.adminUrl}/routes/${routeId}`, config);
    return response.data;
  }
  
  async deleteRoute(routeId: string): Promise<void> {
    await axios.delete(`${this.adminUrl}/routes/${routeId}`);
  }
}

// 使用
const routeManager = new KongRouteManager();

// 创建用户路由
await routeManager.createRoute('user-service', {
  name: 'user-routes',
  paths: ['/api/users'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  strip_path: false,
  preserve_host: false
});

// 创建特定用户路由
await routeManager.createRoute('user-service', {
  name: 'user-by-id',
  paths: ['/api/users/:id'],
  methods: ['GET', 'PUT', 'DELETE']
});

插件配置

// kong-plugin.ts
export class KongPluginManager {
  private adminUrl: string;
  
  constructor(adminUrl: string = 'http://localhost:8001') {
    this.adminUrl = adminUrl;
  }
  
  async enablePluginForService(serviceId: string, pluginName: string, config: any): Promise<any> {
    const response = await axios.post(
      `${this.adminUrl}/services/${serviceId}/plugins`,
      {
        name: pluginName,
        config
      }
    );
    return response.data;
  }
  
  async enablePluginForRoute(routeId: string, pluginName: string, config: any): Promise<any> {
    const response = await axios.post(
      `${this.adminUrl}/routes/${routeId}/plugins`,
      {
        name: pluginName,
        config
      }
    );
    return response.data;
  }
  
  async enableGlobalPlugin(pluginName: string, config: any): Promise<any> {
    const response = await axios.post(
      `${this.adminUrl}/plugins`,
      {
        name: pluginName,
        config
      }
    );
    return response.data;
  }
  
  async listPlugins(): Promise<any[]> {
    const response = await axios.get(`${this.adminUrl}/plugins`);
    return response.data.data;
  }
}

// 使用
const pluginManager = new KongPluginManager();

// 启用速率限制
await pluginManager.enablePluginForService('user-service', 'rate-limiting', {
  minute: 100,
  hour: 1000,
  policy: 'local',
  fault_tolerant: true
});

// 启用 JWT 认证
await pluginManager.enablePluginForService('user-service', 'jwt', {
  key_claim_name: 'sub',
  claims_to_verify: ['exp']
});

// 启用 CORS
await pluginManager.enableGlobalPlugin('cors', {
  origins: ['*'],
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  headers: ['Accept', 'Content-Type', 'Authorization'],
  exposed_headers: ['X-Total-Count'],
  max_age: 3600,
  credentials: true
});

NGINX 作为 API 网关

NGINX 配置

# nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream user_service {
        least_conn;
        server user-service-1:3000 weight=3;
        server user-service-2:3000 weight=2;
        server user-service-3:3000 weight=1;
        
        keepalive 32;
    }

    upstream order_service {
        least_conn;
        server order-service-1:3000;
        server order-service-2:3000;
        
        keepalive 32;
    }

    # 速率限制区
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    server {
        listen 80;
        server_name api.example.com;

        # 安全头
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;

        # CORS
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

        # 处理预检请求
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }

        # 用户服务路由
        location /api/users {
            limit_req zone=api_limit burst=20 nodelay;
            
            proxy_pass http://user_service;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            
            proxy_connect_timeout 60s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
        }

        # 订单服务路由
        location /api/orders {
            limit_req zone=api_limit burst=20 nodelay;
            
            proxy_pass http://order_service;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            
            proxy_connect_timeout 60s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
        }

        # 健康检查端点
        location /health {
            access_log off;
            return 200 "healthy
";
            add_header Content-Type text/plain;
        }

        # 错误页面
        error_page 502 503 504 /50x.html;
        location = /50x.html {
            root /usr/share/nginx/html;
            internal;
        }
    }
}

动态配置

// nginx-config-generator.ts
export interface UpstreamConfig {
  name: string;
  servers: Array<{ host: string; port: number; weight?: number }>;
  algorithm: 'round-robin' | 'least_conn' | 'ip_hash';
}

export interface RouteConfig {
  path: string;
  upstream: string;
  methods?: string[];
  rateLimit?: { zone: string; rate: string; burst: number };
}

export class NginxConfigGenerator {
  generateUpstream(config: UpstreamConfig): string {
    const servers = config.servers.map(server => {
      const weight = server.weight ? ` weight=${server.weight}` : '';
      return `        server ${server.host}:${server.port}${weight};`;
    }).join('
');

    return `upstream ${config.name} {
        ${config.algorithm};
${servers}
        keepalive 32;
    }`;
  }

  generateLocation(config: RouteConfig): string {
    const methods = config.methods ? `        if ($request_method !~ "^(${config.methods.join('|')})$") { return 405; }
` : '';
    const rateLimit = config.rateLimit 
      ? `        limit_req zone=${config.rateLimit.zone} rate=${config.rateLimit.rate} burst=${config.rateLimit.burst} nodelay;
` 
      : '';

    return `location ${config.path} {
${methods}${rateLimit}        proxy_pass http://${config.upstream};
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }`;
  }

  generateConfig(upstreams: UpstreamConfig[], routes: RouteConfig[]): string {
    const upstreamBlock = upstreams.map(u => this.generateUpstream(u)).join('

');
    const locationBlock = routes.map(r => this.generateLocation(r)).join('

');

    return `events {
    worker_connections 1024;
}

http {
${upstreamBlock}

    server {
        listen 80;
        server_name api.example.com;

${locationBlock}
    }
}`;
  }
}

// 使用
const generator = new NginxConfigGenerator();

const config = generator.generateConfig(
  [
    {
      name: 'user_service',
      servers: [
        { host: 'user-service-1', port: 3000, weight: 3 },
        { host: 'user-service-2', port: 3000, weight: 2 }
      ],
      algorithm: 'least_conn'
    }
  ],
  [
    {
      path: '/api/users',
      upstream: 'user_service',
      methods: ['GET', 'POST'],
      rateLimit: { zone: 'api_limit', rate: '10r/s', burst: 20 }
    }
  ]
);

功能

认证

// gateway-auth.ts
export interface AuthConfig {
  type: 'jwt' | 'oauth2' | 'basic' | 'api-key';
  config: Record<string, any>;
}

export class GatewayAuth {
  constructor(private kongManager: KongPluginManager) {}
  
  async setupJWT(serviceId: string, config: any): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'jwt', {
      key_claim_name: 'sub',
      secret_is_base64: false,
      claims_to_verify: ['exp'],
      cookie_names: ['jwt'],
      uri_param_names: ['jwt']
    });
  }
  
  async setupOAuth2(serviceId: string, config: any): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'oauth2', {
      scopes: ['read', 'write'],
      mandatory_scope: true,
      enable_authorization_code: true,
      enable_client_credentials: true,
      enable_implicit_grant: false,
      enable_password_grant: false
    });
  }
  
  async setupBasicAuth(serviceId: string): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'basic-auth', {
      hide_credentials: true
    });
  }
  
  async setupAPIKey(serviceId: string): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'key-auth', {
      key_names: ['apikey', 'X-API-Key'],
      hide_credentials: true
    });
  }
}

速率限制

// gateway-rate-limit.ts
export interface RateLimitConfig {
  minute?: number;
  hour?: number;
  day?: number;
  policy: 'local' | 'redis' | 'cluster';
  faultTolerant: boolean;
}

export class GatewayRateLimit {
  constructor(private kongManager: KongPluginManager) {}
  
  async setupRateLimit(serviceId: string, config: RateLimitConfig): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'rate-limiting', {
      minute: config.minute,
      hour: config.hour,
      day: config.day,
      policy: config.policy,
      fault_tolerant: config.faultTolerant,
      redis_host: process.env.REDIS_HOST || 'localhost',
      redis_port: parseInt(process.env.REDIS_PORT || '6379'),
      redis_password: process.env.REDIS_PASSWORD,
      redis_database: parseInt(process.env.REDIS_DB || '0')
    });
  }
  
  async setupRateLimitByIP(serviceId: string, config: RateLimitConfig): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'rate-limiting', {
      ...config,
      limit_by: 'ip'
    });
  }
  
  async setupRateLimitByConsumer(serviceId: string, config: RateLimitConfig): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'rate-limiting', {
      ...config,
      limit_by: 'consumer'
    });
  }
}

请求/响应转换

// gateway-transformation.ts
export interface TransformConfig {
  add?: { headers?: Record<string, string>; querystring?: Record<string, string> };
  remove?: { headers?: string[]; querystring?: string[]; body?: string[] };
  replace?: { headers?: Record<string, string>; body?: Record<string, string> };
}

export class GatewayTransformation {
  constructor(private kongManager: KongPluginManager) {}
  
  async setupRequestTransform(serviceId: string, config: TransformConfig): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'request-transformer', {
      add: config.add,
      remove: config.remove,
      replace: config.replace
    });
  }
  
  async setupResponseTransform(serviceId: string, config: TransformConfig): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'response-transformer', {
      add: config.add,
      remove: config.remove,
      replace: config.replace
    });
  }
  
  async setupBodyTransform(serviceId: string, config: any): Promise<void> {
    await this.kongManager.enablePluginForService(serviceId, 'request-transformer', {
      append: {
        body: config.append
      }
    });
  }
}

路由策略

基于路径的路由

// path-routing.ts
export interface PathRoute {
  path: string;
  service: string;
  stripPath: boolean;
}

export class PathRouter {
  async setupRoutes(routes: PathRoute[]): Promise<void> {
    const kong = new KongServiceManager();
    const routeManager = new KongRouteManager();
    
    for (const route of routes) {
      // 确保服务存在
      const services = await kong.listServices();
      const service = services.find(s => s.name === route.service);
      
      if (!service) {
        throw new Error(`Service ${route.service} not found`);
      }
      
      // 创建路由
      await routeManager.createRoute(service.id, {
        name: `${route.service}-route`,
        paths: [route.path],
        strip_path: route.stripPath,
        preserve_host: false
      });
    }
  }
}

// 使用
const router = new PathRouter();
await router.setupRoutes([
  {
    path: '/api/v1/users',
    service: 'user-service',
    stripPath: false
  },
  {
    path: '/api/v1/orders',
    service: 'order-service',
    stripPath: false
  }
]);

基于头部的路由

// header-routing.ts
export interface HeaderRoute {
  name: string;
  headers: Record<string, string>;
  service: string;
}

export class HeaderRouter {
  async setupRoutes(routes: HeaderRoute[]): Promise<void> {
    const kong = new KongServiceManager();
    const routeManager = new KongRouteManager();
    
    for (const route of routes) {
      const services = await kong.listServices();
      const service = services.find(s => s.name === route.service);
      
      if (!service) {
        throw new Error(`Service ${route.service} not found`);
      }
      
      // 创建带有头部匹配的路由
      await routeManager.createRoute(service.id, {
        name: route.name,
        headers: Object.entries(route.headers).map(([name, value]) => ({
          name,
          value
        })),
        strip_path: false
      });
    }
  }
}

// 使用
const router = new HeaderRouter();
await router.setupRoutes([
  {
    name: 'mobile-route',
    headers: { 'X-Client-Type': 'mobile' },
    service: 'mobile-service'
  },
  {
    name: 'web-route',
    headers: { 'X-Client-Type': 'web' },
    service: 'web-service'
  }
]);

安全

安全头

// security-headers.ts
export class SecurityHeaders {
  static getHeaders(): Record<string, string> {
    return {
      'X-Frame-Options': 'SAMEORIGIN',
      'X-Content-Type-Options': 'nosniff',
      'X-XSS-Protection': '1; mode=block',
      'Referrer-Policy': 'strict-origin-when-cross-origin',
      'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
      'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
    };
  }
  
  static setupCORS(allowedOrigins: string[]): Record<string, string> {
    return {
      'Access-Control-Allow-Origin': allowedOrigins.join(','),
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      'Access-Control-Allow-Credentials': 'true',
      'Access-Control-Max-Age': '86400'
    };
  }
}

监控

指标收集

// gateway-metrics.ts
import promClient from 'prom-client';

export class GatewayMetrics {
  private requestCounter: promClient.Counter;
  private responseTime: promClient.Histogram;
  private errorCounter: promClient.Counter;
  
  constructor() {
    this.requestCounter = new promClient.Counter({
      name: 'gateway_requests_total',
      help: '总请求数',
      labelNames: ['service', 'method', 'status']
    });
    
    this.responseTime = new promClient.Histogram({
      name: 'gateway_response_time_seconds',
      help: '响应时间(秒)',
      labelNames: ['service', 'method'],
      buckets: [0.01, 0.05, 0.1, 0.5, 1, 5]
    });
    
    this.errorCounter = new promClient.Counter({
      name: 'gateway_errors_total',
      help: '总错误数',
      labelNames: ['service', 'error_type']
    });
  }
  
  recordRequest(service: string, method: string, status: number): void {
    this.requestCounter.inc({ service, method, status: status.toString() });
  }
  
  recordResponseTime(service: string, method: string, duration: number): void {
    this.responseTime.observe({ service, method }, duration);
  }
  
  recordError(service: string, errorType: string): void {
    this.errorCounter.inc({ service, error_type: errorType });
  }
  
  getMetrics(): string {
    return promClient.register.metrics();
  }
}

高可用性

负载均衡

// load-balancer.ts
export interface LoadBalancerConfig {
  algorithm: 'round-robin' | 'least-connections' | 'ip-hash' | 'consistent-hash';
  healthCheck: {
    enabled: boolean;
    interval: number;
    timeout: number;
    unhealthyThreshold: number;
    healthyThreshold: number;
  };
}

export class LoadBalancer {
  setupLoadBalancer(upstreamName: string, targets: string[], config: LoadBalancerConfig): string {
    const targetsBlock = targets.map(target => `        server ${target};`).join('
');
    
    return `upstream ${upstreamName} {
        ${config.algorithm};
${targetsBlock}
        
        keepalive 32;
    }`;
  }
}

// 使用
const lb = new LoadBalancer();
const config = lb.setupLoadBalancer('user_service', [
  'user-service-1:3000',
  'user-service-2:3000',
  'user-service-3:3000'
], {
  algorithm: 'least-connections',
  healthCheck: {
    enabled: true,
    interval: 30,
    timeout: 5,
    unhealthyThreshold: 3,
    healthyThreshold: 2
  }
});

生产部署

Docker Compose 生产配置

# docker-compose.prod.yml
version: '3.8'

services:
  kong:
    image: kong/kong-gateway:3.4
    ports:
      - "80:8000"
      - "443:8443"
      - "8444:8001"
    environment:
      KONG_DATABASE: "postgres"
      KONG_PG_HOST: kong-db
      KONG_PG_DATABASE: kong
      KONG_PG_USER: kong
      KONG_PG_PASSWORD: ${KONG_PG_PASSWORD}
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stdout
      KONG_ADMIN_ERROR_LOG: /dev/stdout
      KONG_ADMIN_LISTEN: "0.0.0.0:8001"
      KONG_ADMIN_GUI_URL: "http://localhost:8002"
      KONG_SSL: "on"
      KONG_SSL_CERT: /etc/kong/tls/kong.crt
      KONG_SSL_CERT_KEY: /etc/kong/tls/kong.key
    volumes:
      - ./tls:/etc/kong/tls
    depends_on:
      - kong-db
    networks:
      - gateway-net
    restart: unless-stopped

  kong-db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: kong
      POSTGRES_USER: kong
      POSTGRES_PASSWORD: ${KONG_PG_PASSWORD}
    volumes:
      - kong-data:/var/lib/postgresql/data
    networks:
      - gateway-net
    restart: unless-stopped

  konga:
    image: pantsel/konga:next
    ports:
      - "8002:1337"
    environment:
      NODE_ENV: production
      DB_ADAPTER: postgres
      DB_URI: postgresql://kong:${KONG_PG_PASSWORD}@kong-db:5432/konga
    depends_on:
      - kong-db
    networks:
      - gateway-net
    restart: unless-stopped

volumes:
  kong-data:

networks:
  gateway-net:
    driver: bridge

最佳实践

API 网关检查清单

## API 网关最佳实践检查清单

### 配置
- [ ] 定义清晰的路由规则
- [ ] 设置服务发现
- [ ] 配置负载均衡
- [ ] 启用健康检查

### 安全
- [ ] 实施认证
- [ ] 启用速率限制
- [ ] 添加安全头
- [ ] 正确配置 CORS
- [ ] 启用 HTTPS/TLS

### 性能
- [ ] 启用缓存
- [ ] 配置超时
- [ ] 设置压缩
- [ ] 优化连接池

### 监控
- [ ] 启用访问日志
- [ ] 设置指标收集
- [ ] 配置告警
- [ ] 监控错误率

### 可靠性
- [ ] 设置断路器
- [ ] 配置重试
- [ ] 启用优雅降级
- [ ] 规划高可用性

额外资源