反向代理与 API 网关是微服务架构的流量中枢:客户端只与一个入口打交道,真正的业务集群躲在代理之后。从最简单的 Nginx 到云原生时代的 Kong、Envoy,理解这一层的能力边界与取舍,是后端架构师的必修课。
一、反向代理核心职责
1.1 正向代理与反向代理
正向代理(代理客户端,翻墙/抓包场景):
客户端 A ─┐
客户端 B ─┼─→ 正向代理 ─→ 目标服务器
客户端 C ─┘ ↑
代表客户端发起请求
反向代理(代理服务端,业务入口场景):
客户端 ─→ 反向代理(统一入口 80/443)
├─→ 后端节点 1
├─→ 后端节点 2
└─→ 后端节点 3
代表服务端对外提供服务
一句话:正向代理隐藏客户端,反向代理隐藏服务端。
1.2 反向代理承担的工作
| 职责 | 说明 | 典型实现 |
|---|---|---|
| 请求转发 | 按规则分发到后端节点 | proxy_pass / upstream |
| 负载均衡 | 轮询、加权、哈希等 | Nginx 内置策略 |
| TLS 终止 | 统一卸载 HTTPS,后端走明文 | 证书挂在代理层 |
| 健康检查 | 摘除故障节点 | 主动探测 / 被动失败计数 |
| 缓存 | 静态资源与响应缓存 | proxy_cache |
| 安全防护 | 限流、IP 黑名单、WAF | limit_req / 第三方模块 |
| 协议转换 | WebSocket 升级、gRPC 透传 | http1.1 upgrade / grpc_pass |
二、Nginx 配置实战
2.1 upstream 与转发
# 全局 http 块
http {
# 动态上游:按权重负载均衡 + 被动健康检查
upstream backend_api {
server 192.168.1.11:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.12:8080 weight=3 max_fails=3 fail_timeout=30s;
server 192.168.1.13:8080 backup; # 冷备节点
keepalive 32; # 与后端的长连接池
keepalive_timeout 60s;
}
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://backend_api;
proxy_http_version 1.1;
proxy_set_header Connection "";
# 透传关键头
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 5s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
}
}
}
2.2 主动健康检查(商业版/openresty 特性)
开源 Nginx 被动健康检查依赖请求失败计数,主动健康检查可用 OpenResty + lua-resty-healthcheck 或第三方补丁:
# 简单请求级健康检查:给 /healthz 单独分组
upstream backend_api {
server 192.168.1.11:8080;
server 192.168.1.12:8080;
zone upstream_backend 64k; # 共享内存,配合 nginx-plus/openresty
}
server {
location = /healthz {
# 该请求专门用于健康探测
access_log off;
proxy_pass http://backend_api;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
}
}
2.3 限流配置
http {
# 定义限流区域:1r/s 平均速率,突发 5
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=1r/s;
# 定义并发连接限制
limit_conn_zone $binary_remote_addr zone=per_ip_conn:10m;
server {
listen 80;
location /api/ {
# 漏桶限流,超过突发返回 503
limit_req zone=api_limit burst=5 nodelay;
limit_req_status 429;
# 每 IP 最多 20 并发
limit_conn per_ip_conn 20;
limit_conn_status 429;
proxy_pass http://backend_api;
}
# 静态资源不限流
location /static/ {
alias /data/static/;
expires 30d;
}
}
}
一句话:
limit_req_zone定义共享内存桶,burst缓冲突发流量,nodelay决定突发是否立即放行。
三、Kong 网关能力
3.1 架构模型
Kong 基于 Nginx + OpenResty + Lua,插件化地提供认证、限流、转换等能力,配置存储在后端数据库(PostgreSQL/Cassandra)中,支持声明式配置。
客户端 → Kong 网关(数据面,Nginx 内核)
│ DB-less 模式:配置通过 Admin API 下发
├─→ 插件链:key-auth → rate-limiting → ...
└─→ 上游服务(可多版本、加权)
Administrator → Admin API / declarative.yaml
3.2 声明式配置示例
# declarative.yaml(DB-less 模式)
_format_version: "2.1"
services:
- name: order-service
url: http://order-svc:8080
routes:
- name: order-route
paths: ["/orders"]
methods: ["GET", "POST"]
strip_path: true
plugins:
- name: rate-limiting
config:
minute: 60
hour: 3000
policy: local
- name: key-auth
config:
key_names: ["apikey"]
consumers:
- username: partner-a
keyauth_credentials:
- key: secret-key-001
3.3 Kong 常用插件清单
| 类别 | 插件 | 作用 |
|---|---|---|
| 认证 | key-auth / jwt / oauth2 / basic-auth | 多种认证协议 |
| 安全 | ip-restriction / bot-detection / cors | IP 白名单、反爬、跨域 |
| 流量 | rate-limiting / proxy-cache / request-transformer | 限流、缓存、改写 |
| 可观测 | prometheus / zipkin / file-log | 指标、链路、日志 |
| 转换 | response-transformer / correlation-id | 响应改写、注入链路 ID |
四、Envoy 网关能力
4.1 核心抽象
Envoy 是 CNCF 孵化的高性能代理,面向 Service Mesh 设计,配置完全由 API 动态下发(xDS),支持 gRPC、HTTP/2、HTTP/3、HTTP/1.1 全栈协议。
# 最小 Envoy 静态配置(示例)
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 10000 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
http_filters:
- name: envoy.filters.http.router
route_config:
virtual_hosts:
- name: vh
domains: ["*"]
routes:
- match: { prefix: "/api" }
route:
cluster: backend
clusters:
- name: backend
connect_timeout: 5s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: backend
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: backend, port_value: 8080 }
4.2 Envoy vs Kong vs Nginx
| 维度 | Nginx | Kong | Envoy |
|---|---|---|---|
| 内核 | 原生 C | Nginx + OpenResty(Lua) | C++ |
| 动态配置 | reload | Admin API / DB-less | xDS 热更新 |
| 扩展方式 | 模块(C)/ Lua | Lua 插件 | Lua/WASM Filter |
| 协议支持 | HTTP/1.1、HTTP/2 | 同 Nginx + 部分 gRPC | HTTP/1.1/2/3、gRPC、Thrift |
| 服务发现 | 静态/DNS | 静态/DNS/Consul | EDS/xDS 原生 |
| 定位 | 反向代理/负载均衡 | 企业级 API 网关 | 云原生数据面(网格) |
一句话:Nginx 是「灵活的代理」,Kong 是「开箱即用的网关平台」,Envoy 是「为动态网格而生的数据面」。
五、网关层流量治理
5.1 熔断、重试与超时
流量治理三件套需要在网关统一配置,避免每个业务各自为政:
# Envoy route 上的治理配置
routes:
- match: { prefix: "/api/order" }
route:
cluster: order_cluster
timeout: 10s
retry_policy:
retry_on: "connect-failure,reset,5xx"
num_retries: 3
retry_host_predicate:
- name: envoy.retry_host_predicates.previous_hosts
per_try_timeout: 3s
circuit_breakers:
thresholds:
- priority: DEFAULT
max_connections: 10000
max_pending_requests: 5000
max_requests: 10000
max_retries: 3
5.2 网关层鉴权模式
模式一:网关统一鉴权(集中式)
客户端 → 网关(JWT 校验) → 后端(信任网关,跳过鉴权)
优点:后端简单;缺点:网关成为安全焦点
模式二:网关透传,后端各自鉴权(分散式)
客户端 → 网关(透传 Token) → 每个服务自行校验
优点:安全边界内聚;缺点:重复实现
模式三:集中鉴权服务 + 网关缓存
客户端 → 网关 → 鉴权服务(JWT/ACL) → 网关缓存结果 → 后端
5.3 JWT 网关校验示例(Kong jwt 插件 + Go)
// 网关层面校验 JWT 后,将解析出的用户信息以请求头透传给后端
package main
import (
"fmt"
"github.com/golang-jwt/jwt/v5"
)
// 校验并提取 claims(网关侧伪代码)
func verifyAndForward(token string) error {
claims := jwt.MapClaims{}
_, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) {
return []byte("gateway-secret"), nil
})
if err != nil {
return fmt.Errorf("token invalid: %w", err)
}
// 通过 X-User-ID / X-User-Role 透传给下游
// header.Set("X-User-ID", claims["sub"].(string))
return nil
}
六、WebSocket 与 gRPC 代理
6.1 WebSocket 升级代理
WebSocket 靠 HTTP Upgrade 协议升级,代理必须放行 101 状态码与升级头:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream ws_backend {
server 192.168.1.21:9000;
server 192.168.1.22:9000;
}
server {
listen 80;
location /ws/ {
proxy_pass http://ws_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# 长连接超时:覆盖默认 60s,防止空闲被切断
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
# 支持粘性会话:同一连接固定到同一节点
sticky cookie ws_route expires=1h;
}
}
一句话:代理 WebSocket 的关键是透传
Upgrade/Connection头并把读超时调大到小时级。
6.2 gRPC 代理
gRPC 是 HTTP/2 之上的二进制 RPC,代理层必须走 HTTP/2:
http {
# gRPC 需要 HTTP/2 与 ssl
server {
listen 443 ssl http2;
server_name grpc.example.com;
ssl_certificate /etc/nginx/tls/server.crt;
ssl_certificate_key /etc/nginx/tls/server.key;
# 监听 gRPC 端口(默认 50051 示例)
location /helloworld.Greeter/ {
grpc_pass grpc://grpc_backend;
}
}
upstream grpc_backend {
server 192.168.1.31:50051;
server 192.168.1.32:50051;
}
}
6.3 协议代理对比
| 协议 | 代理要点 | 常见问题 |
|---|---|---|
| HTTP/1.1 | 转发头、超时 | 长连接被切断、头透传缺失 |
| HTTP/2 | 多路复用、连接复用 | 需支持 h2c/h2 协商 |
| WebSocket | 升级头、大超时、粘性 | 超时误断、节点漂移 |
| gRPC | HTTP/2 + 流式语义 | 需 HTTP/2、禁用 buffer 类改造 |
| TCP/UDP (L4) | 四层透传、会话保持 | 无法按 URL 路由 |
七、网关选型决策表
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 单体 + 静态资源入口 | Nginx | 轻量、稳定、配置简单 |
| 微服务 + 统一鉴权限流 | Kong | 插件生态成熟、管理界面友好 |
| K8s + Service Mesh 规划 | Envoy/Istio | 云原生标准、动态下发 |
| 极高性能四层分发 | LVS/DPDK、Envoy L4 | 用户态网络栈极致吞吐 |
| 混合协议(HTTP+gRPC+WS) | Envoy / Nginx | 全协议原生支持 |
| 有团队维护 Lua/WASM | Kong / Envoy 二次开发 | 深度定制需求 |
选型建议三步法:
- 先看协议需求:是否含 gRPC/HTTP/3、是否大量 WebSocket;
- 再看运维模式:静态配置可接受 vs 需要动态灰度;
- 最后看生态:团队是否已有 Nginx/OpenResty 经验、是否要进 Service Mesh。
八、总结
| 能力 | Nginx | Kong | Envoy |
|---|---|---|---|
| 反向代理 | ★★★ | ★★★ | ★★★ |
| API 网关功能 | ★★ | ★★★ | ★★ |
| 动态配置 | ★ | ★★★ | ★★★ |
| 云原生集成 | ★ | ★★ | ★★★ |
| 学习/运维成本 | 低 | 中 | 高 |
反向代理解决「流量怎么进」,API 网关解决「流量怎么管」。生产架构中常常两者共存:最外层用 Nginx/云负载均衡做 TLS 终止与静态加速,内层用 Kong/Envoy 做路由、鉴权、限流、灰度。无论选型如何,把健康检查、超时、熔断、重试、可观测这五项治理能力补齐,网关才能真正成为高可用架构的稳定基座。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。