Skip to main content
LadeStack LogoLadeStack
Microservices 约 9 分钟 2024年9月15日

构建微服务API网关:路由、身份认证、速率限制与系统韧性

涵盖反向代理、分布式认证、Redis令牌桶限流、断路器、Envoy配置以及服务网格对比的企业级微服务API网关架构指南。

微服务API网关架构图

1. 引言:为什么微服务架构必须采用API网关

在现代分布式微服务架构中,如果让客户端(Web前端、移动App、第三方集成系统)直接与后端数十乃至上百个细粒度微服务通信,将构成严重的架构反模式。

直接通信模型会导致以下典型故障:

  • 客户端与后端服务高度耦合: 服务的任何拆分、重命名或路由变更都必须强制更新客户端代码。
  • 安全攻击面急剧扩大: 每个内部微服务都必须直接暴露于公网,导致防火墙规则、CORS配置与SSL/TLS证书管理极度碎片化。
  • 横切关注点重复开发: 每个微服务团队都在重复编写JWT校验、速率限制与请求审计逻辑,不仅浪费资源且极易引入安全漏洞。
  • 高延迟与过度网络往返: 移动端为了渲染一个综合页面,需要通过低带宽移动网络串行发起10次以上的HTTP请求。
直接连接 vs API网关模式对比
============================
直接通信(反模式):
[移动App客户端] ──┬──► [认证服务 :8081]
                  ├──► [订单服务 :8082]
                  ├──► [支付服务 :8083]
                  └──► [库存服务 :8084]

API网关模式(推荐模式):
                  ┌────────────────────────────────────────────────────────┐
                  │                 API网关集群 (:443)                      │
                  │  - SSL终结 & CORS跨域策略                              │
                  │  - JWT签名加密验证 & 身份声明向下游透传                 │
                  │  - 基于Redis的分布式令牌桶速率限制                      │
                  │  - 动态路由、智能超时控制与断路器熔断                   │
                  └──────────────────────────┬─────────────────────────────┘
                                             │ 内部私有VPC网络 (mTLS)
                        ┌────────────────────┼────────────────────┐
                        ▼                    ▼                    ▼
                  [认证服务]             [订单服务]           [支付服务]

API网关充当系统边界的单一反向代理入口,集中处理所有跨服务通用能力。


2. 生产级API网关核心架构分层

成熟的生产级网关必须在纳秒至毫秒级延迟内完成以下核心处理流程:

功能分层 网关核心职责 实现机制与协议
反向代理与动态路由 将客户端外部路径映射至内部私有微服务地址 前缀匹配、正则路由、金丝雀权重分流
边缘安全与身份认证 校验请求数字签名,提取身份元数据并向下透传 JWT RS256/EdDSA验证、JWKS密钥轮换、双向mTLS
流量治理与防刷限制 保护后端防范拒绝服务攻击,实施租户配额 Redis分布式令牌桶算法、滑动窗口计数器
系统弹性与韧性控制 阻断雪崩级联故障,吸收瞬时网络抖动 请求超时控制、幂等性指数退避重试、熔断断路器
全链路可观测性 跨分布式调用链串联请求上下文 遵循W3C TraceContext标准 (traceparent)、OpenTelemetry
协议适配与转换 解耦外部客户端与内部高性能通信协议 外部HTTP/1.1・HTTP/2转内部高性能gRPC/Protobuf

3. 身份认证与深度防御(Defense in Depth)

关键架构原则:网关身份验证决不能替代下游微服务授权

许多团队常犯一个严重错误:“既然请求已经在API网关通过了JWT验证,那么内部微服务就无需再次校验权限了”。

这是一种极其危险的假设。一旦网关被攻陷,或者攻击者通过内网侧向渗透直接向内部微服务发送伪造请求,整个系统将门户大开。必须践行深度防御(Defense in Depth):

深度防御身份流转时序
--------------------
[外部客户端]
      │ 1. Authorization: Bearer <JWT>
      ▼
[API网关]
      │ 2. 使用本地缓存的JWKS公钥验证JWT数字签名
      │ 3. 校验exp有效期与iss发行方,伪造或过期凭据直接返回401 Unauthorized
      │ 4. 剥离外部敏感信息,将验证通过的声明注入受信任内部请求头:
      │    - X-User-Id: 98412
      │    - X-User-Roles: billing_admin,user
      │    - X-Tenant-Id: tenant_corp_a
      ▼
[下游微服务 (订单/结算)]
      │ 5. 校验mTLS网络凭证,确保请求确实来自网关
      │ 6. 根据内部X-User-Roles头在本地进行细粒度业务资源授权(Authorization)
      │ 7. 执行核心业务逻辑

4. 分布式速率限制:Redis令牌桶算法

单机内存限流在容器水平自动扩缩容(HPA)环境中无法正常工作——随着容器副本数从2个扩展到20个,总体限流配额将扩大10倍,彻底失去防护意义。

通过在集中式Redis集群上执行原子性Lua脚本,可以在微秒级完成严格的令牌桶限流:

-- Redis Token Bucket Rate Limiting (Atomic Lua Script)
-- KEYS[1]: 限流键 (例如: ratelimit:tenant_123:orders)
-- ARGV[1]: 桶最大容量 (Max Burst)
-- ARGV[2]: 令牌填充速率 (Tokens/Second)
-- ARGV[3]: 当前Unix时间戳 (秒)
-- ARGV[4]: 本次请求消耗令牌数 (通常为 1)

local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local fill_rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4])

local data = redis.call('HMGET', key, 'tokens', 'last_updated')
local tokens = tonumber(data[1])
local last_updated = tonumber(data[2])

if not tokens then
    tokens = capacity
    last_updated = now
else
    local elapsed = math.max(0, now - last_updated)
    tokens = math.min(capacity, tokens + (elapsed * fill_rate))
    last_updated = now
end

if tokens >= requested then
    tokens = tokens - requested
    redis.call('HMSET', key, 'tokens', tokens, 'last_updated', last_updated)
    redis.call('EXPIRE', key, math.ceil(capacity / fill_rate) * 2)
    return {1, math.floor(tokens)} -- 1 = 放行, 返回剩余令牌数
else
    redis.call('HMSET', key, 'tokens', tokens, 'last_updated', last_updated)
    return {0, 0} -- 0 = 拒绝 (429 Too Many Requests)
end

5. 韧性治理:超时、重试与熔断断路器

断路器状态转换模型
------------------
       ┌────────── 错误率超过阈值 (例如连续失败超50%) ──────────┐
       │                                                        │
       ▼                                                        │
 ┌───────────┐         冷却时间到期 (例如30秒后)           ┌───────────┐
 │   OPEN    │ ──────────────────────────────────────────► │ HALF-OPEN │
 └───────────┘                                             └───────────┘
       ▲                                                        │
       │               ┌────── 试探请求探测成功 ────────────────┘
       │               ▼
 ┌───────────┐
 │  CLOSED   │ (正常放行流量)
 └───────────┘
  1. 上游超时保护: 网关等待下游微服务响应的超时时间必须严格短于下游业务内部处理超时,防止网关连接池被打满。
  2. 幂等性重试策略: 严禁对非幂等HTTP操作(如POST支付请求)执行自动重试,重试必须仅限于GET、PUT等幂等请求并配合指数退避。
  3. 断路器熔断保护: 当某个下游服务持续超时或返回5xx时,断路器进入OPEN状态,快速失败并返回降级兜底数据。

6. 主流网关技术选型对比:Envoy vs NGINX vs Kong

评测维度 Envoy Proxy NGINX (Open Source / Plus) Kong Gateway
底层实现 C++ (极致内存局部性与极低延迟) C (高并发事件驱动模型) Lua / OpenResty (基于NGINX内核)
配置动态性 动态控制面 (基于xDS API无重启热更新) 静态配置 (修改配置需重载Master进程) 动态管理 (REST API与声明式decK工具)
原生协议 HTTP/1.1, HTTP/2, HTTP/3, gRPC HTTP/1.1, HTTP/2, gRPC代理 HTTP/1.1, HTTP/2, gRPC
插件扩展 WebAssembly (Wasm)、C++过滤器 C扩展模块、njs (JavaScript) Lua插件、Wasm模块
适用场景 云原生Kubernetes Ingress、服务网格 高性能静态文件分发、简易反向代理 企业级API开放平台与丰富插件生态

7. API网关与服务网格(Service Mesh)的关系

两者不是替代关系,而是互补共生:

  • API网关(南北向流量): 管理从外部客户端进入内部数据中心的边缘边界流量,侧重于外部鉴权、按调用量计费、API版本控制与外部契约。
  • 服务网格(东西向流量): 管理内部微服务之间的横向通信(如Istio、Linkerd),侧重于服务间双向mTLS无感加密、细粒度金丝雀流量切分与细致指标监控。

8. 生产部署核验清单

  1. 消除单点故障: 网关多副本跨可用区(AZ)部署,前端挂接高可用云负载均衡器。
  2. JWKS异步化验证: 网关验证JWT必须使用异步预加载的本地公钥缓存,严禁每次请求同步调用授权服务器。
  3. 严格内部防线: 内部微服务间通信强制启用双向mTLS与角色权限验证。
  4. 全链路追踪贯通: 网关注入符合W3C规范的traceparent请求头,贯通下游所有日志与链路追踪系统。

More Engineering Articles