API 网关与限流:Kong、Nginx 实现流量控制

FreeGuideOnline 最新 2026-06-13

什么是 API 网关

API 网关是位于客户端与后端服务之间的中间层,负责统一处理所有外部请求。它的核心职责包括:

  • 路由转发:根据请求路径、头部等信息将流量导向正确的服务。
  • 安全防护:实施认证、授权、IP 黑白名单等策略。
  • 流量控制:对请求进行限流、熔断和负载均衡。
  • 可观测性:集中记录日志、监控指标、分布式追踪。
  • 协议转换:将外部 HTTP/REST 请求转换为内部 gRPC、Thrift 等协议。

当系统规模增长,微服务数量增多时,没有网关会导致每个服务都要独立实现上述能力,产生大量重复工作和管理负担。因此 API 网关已经成为现代分布式架构中的标准组件。

为什么需要限流

限流(Rate Limiting)是保障服务稳定性的关键手段,主要目的是:

  • 防止资源耗尽:避免恶意攻击、爬虫或突发流量打垮后端。
  • 保证公平性:确保每个用户或租户都能获得合理的请求配额。
  • 保护依赖方:当 A 服务调用 B 服务时,A 的限流可以防止 B 被压垮。
  • 成本控制:在云环境中按请求量计费,限流有助于控制开销。

限流通常部署在网关层,因为网关是所有流量的入口,能够做到集中管控,无需改动业务代码。

常见限流算法

在深入具体工具前,先理解几种经典算法,这有助于正确配置限流策略。

固定窗口计数器

将时间划分为固定窗口(如 1 分钟),每个窗口内维护一个计数器。请求到来时计数器加 1,超过阈值则拒绝。

  • 优点:实现简单。
  • 缺点:窗口边界处可能出现流量尖刺(例如 00:00:59 和 00:01:00 两秒内通过两倍阈值)。

滑动窗口计数器

在前一窗口的基础上,按当前窗口已过去的时间比例来估算前一窗口的剩余计数,从而平滑边界效应。

  • 优点:比固定窗口精确。
  • 缺点:仍是一种近似值,不是完全准确。

漏桶

将请求视为水滴,系统有一个固定容量的桶,水滴以恒定速度流出(处理请求)。桶满则请求被丢弃。

  • 优点:输出速率绝对平稳,适合需要整形流量的场景。
  • 缺点:无法应对突发流量(即使后端有能力处理少量爆发)。

令牌桶

系统以固定速率向桶中放入令牌,桶有最大容量。请求需要获取令牌才能被处理,令牌不足时请求被延迟或拒绝。

  • 优点:允许一定程度突发(只要桶中有足够令牌)。
  • 缺点:实现稍复杂。

绝大多数生产级限流组件(包括 Nginx 和 Kong)都基于令牌桶漏桶变体。

使用 Nginx 实现限流

Nginx 本身是一款高性能反向代理服务器,通过内置模块即可完成限流,无需额外插件。

基础限流配置

Nginx 使用 ngx_http_limit_req_module 模块,核心指令有 limit_req_zonelimit_req

一台典型配置如下:

http {
    # 定义限流区域:以客户端IP为键,10MB共享内存,速率10请求/秒
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

    server {
        listen 80;

        location /api/ {
            # 应用限流规则
            limit_req zone=mylimit burst=20 nodelay;

            proxy_pass http://backend;
        }
    }
}

参数解释:

  • $binary_remote_addr:使用二进制IP地址作为限制对象,节省内存。
  • zone=mylimit:10m:分配名为 mylimit 的共享内存区,大小 10MB。
  • rate=10r/s:每秒允许10个请求,采用令牌桶算法,实际是每隔100ms生成一个令牌。
  • burst=20:允许瞬间超过速率限制的额外请求数,构成一个“队列”,由漏桶原理控制。
  • nodelay:突发请求立即处理,不排队等待;如果不加,突发请求会平均间隔延迟处理。

按自定义键限流

可以按 URL、请求头甚至组合变量限流:

# 按请求路径限流
limit_req_zone $uri zone=by_uri:10m rate=5r/s;

# 按自定义Header中的API Key限流
limit_req_zone $http_apikey zone=by_apikey:10m rate=100r/m;

多层级限流

Nginx 支持串联多个限制,比如先按 IP 限制总频次,再按接口路径细粒度限制:

location /api/ {
    limit_req zone=ip_limit burst=5 nodelay;
    limit_req zone=uri_limit burst=10 nodelay;
    proxy_pass http://backend;
}

请求必须同时满足两个区域的限制,否则返回 503(Service Unavailable)。

自定义错误响应

默认限流触发时返回 503,可以自定义状态码和返回体:

location /api/ {
    limit_req zone=mylimit burst=20 nodelay;
    limit_req_status 429;   # 返回 429 Too Many Requests

    proxy_pass http://backend;
}

Nginx 限流的短板

  • 内存限制:状态存储于本地共享内存,多台 Nginx 实例之间无法共享计数。
  • 动态配置:改动通常需要重载配置,不适合频繁变动。
  • 缺乏可视化与监控面板。

面对分布式、大规模场景,通常需要更专业的网关。

使用 Kong 实现限流

Kong 是基于 OpenResty(Nginx+Lua)构建的云原生 API 网关,通过插件系统提供强大的限流能力。

Kong 的限流插件

Kong 提供三个核心限流插件:

  • Rate Limiting:基础限流,支持令牌桶,可按 consumer、credential、IP 等维度。
  • Rate Limiting Advanced:增强版,支持滑动窗口、多维度、Redis/Sentinel 存储等。
  • Request Size Limiting:限制请求体积。

基础限流配置示例

假设已部署好 Kong(Admin API 监听 8001 端口),为一个 Service 添加限流插件:

curl -X POST http://localhost:8001/services/{service_id}/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "rate-limiting",
    "config": {
      "minute": 100,
      "hour": 1000,
      "policy": "local",
      "fault_tolerant": true,
      "hide_client_headers": false
    }
  }'

参数说明:

  • minute:每分钟最多 100 个请求。
  • hour:每小时最多 1000 个请求(两者生效,取更严格者)。
  • policy:计数器存储策略,local 为节点本地内存,cluster 为数据库,redis 为专用 Redis。
  • fault_tolerant:当限流后端(如 Redis)不可用时,是否放行请求。
  • hide_client_headers:是否隐藏返回给客户端的限流头信息。

应用后,Kong 会自动在响应头中加入:

X-RateLimit-Limit-minute: 100
X-RateLimit-Remaining-minute: 99
X-RateLimit-Limit-hour: 1000
X-RateLimit-Remaining-hour: 999

高级限流:按消费方分层

Kong 内置 Consumer 概念,可以绑定 API Key、JWT 等认证。针对不同消费者设定差异化的限流策略:

# 创建一个 Consumer
curl -X POST http://localhost:8001/consumers \
  -d "username=alice"

# 为该 Consumer 创建 API Key
curl -X POST http://localhost:8001/consumers/alice/key-auth

# 在 Route 或 Service 上同时启用 key-auth 和 rate-limiting 插件
curl -X POST http://localhost:8001/routes/{route_id}/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "key-auth"
  }'

# 为这个 Consumer 单独配置限额(覆盖默认值)
curl -X POST http://localhost:8001/consumers/alice/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "rate-limiting-advanced",
    "config": {
      "consumer_groups": null,
      "limit": [5],
      "window_size": [60],
      "window_type": "sliding",
      "retry_after_jitter_max": 0
    }
  }'

这样,alice 的请求会使用专属的限制规则,而其他消费者使用全局默认规则。

使用 Redis 集群实现分布式限流

生产环境中推荐将计数器存储在外部 Redis,确保多节点 Kong 共享计数:

curl -X POST http://localhost:8001/services/{service_id}/plugins \
  -H "Content-Type: application/json" \
  -d '{
    "name": "rate-limiting-advanced",
    "config": {
      "second": 50,
      "policy": "redis",
      "redis_host": "redis-master.example.com",
      "redis_port": 6379,
      "redis_password": "yourpassword",
      "redis_ssl": false,
      "redis_ssl_verify": false,
      "redis_database": 0,
      "redis_timeout": 2000
    }
  }'

插件会使用 Redis 进行原子计数,从而在全集群范围内精准限流。

滑动窗口 vs 令牌桶

rate-limiting-advanced 插件支持 sliding 窗口类型,通过计算过去一段固定窗口内的请求数来判断,可避免固定窗口的边界突发问题。配置:

"window_type": "sliding",
"window_size": [60],   // 窗口长度60秒
"limit": [100]         // 窗口内最多100个请求

令牌桶模式则配置 window_typefixed 或使用原 rate-limiting 插件的 burst 参数。

动态配置与声明式管理

Kong 支持声明式配置文件(kong.yml)和 Admin API,可无缝集成 CI/CD。限流参数变更通过 API 实时生效,无需重启网关。结合监控系统(Prometheus + Grafana),可以直观看到每个路由/消费者的限流状态。

Nginx 与 Kong 限流选择建议

维度 Nginx Kong
部署复杂度 低,单文件配置 较高,需数据库和部署环境
分布式支持 需配合 lua 或外部脚本 原生支持 Redis 集群计数
动态配置 需重载或配合 OpenResty 实时生效,API 驱动
多维度限流 可通过变量组合实现 内置消费者、路由、Service 等
生态与插件 仅有基础模块 丰富插件市场,可扩展
适用场景 小规模、静态限流、简单代理 大型微服务、多租户、复杂策略

如果你的流量规则简单,且仅作为反向代理使用,Nginx 限流足够胜任。如果涉及多个消费者、需要动态策略、可视化、配合认证等功能,Kong 是更优选择。

最佳实践

  1. 为限流设置合理缓冲:使用 burst 让合法突发请求不至于被粗暴拒绝,并结合 nodelay 优化体验。
  2. 返回明确错误信息:设置 Retry-After 头,方便客户端自动重试。
  3. 多粒度分层限流:先按 IP 限制总频率,再按用户或 API Key 限制细分频率。
  4. 监控与告警:采集被拒请求数、剩余配额等指标,配置告警规则。
  5. 优雅降级:当限流计数器存储(Redis)不可用时,设置 fault_tolerant=true 放行请求,避免整体不可用。
  6. 压测验证:上线前用 wrkvegeta 等工具验证阈值是否生效,查看日志是否按预期生效。

快速上手实验

使用 Docker 运行 Nginx 限流示例:

  1. 准备 nginx.conf 文件包含上述限流配置。
  2. 启动容器:docker run -d -p 8080:80 -v $PWD/nginx.conf:/etc/nginx/nginx.conf nginx
  3. ab -n 30 -c 5 http://localhost:8080/api/test 测试,观察 503 响应。

使用 Docker 运行 Kong 限流示例:

# 启动 Kong(需要数据库支撑,Kong 官方提供快速启动脚本)
curl -s https://get.konghq.org/quickstart | bash

# 创建 Service 和 Route
curl -i -X POST http://localhost:8001/services \
  --data name=example-service \
  --data url=http://httpbin.org

curl -i -X POST http://localhost:8001/services/example-service/routes \
  --data paths[]=/mock

# 添加限流插件
curl -i -X POST http://localhost:8001/services/example-service/plugins \
  --data name=rate-limiting \
  --data config.minute=5

# 测试(快速发送请求)
for i in {1..10}; do curl -i http://localhost:8000/mock; done

你会很快看到 429 Too Many Requests 和限流头信息。


掌握这些技能,你将能够为任何规模的 API 系统构建可靠的流量护栏,保护服务韧性,同时维持公平的用户体验。限流不是越严格越好,关键在于理解业务模型后找到那个合理的均衡点。