一句话总结
API Gateway 是微服务的"门面"--外部流量的唯一入口.
它把路由,认证,限流,协议转换等横切关注点从业务服务中剥离出来,让后端服务只专注于业务逻辑.
BFF(Backend for Frontend)则是 Gateway 的变体,为不同客户端量身定制 API.
为什么需要 API Gateway
假设你有 10 个微服务,客户端(Web / App / 小程序)直接调每个服务:
|
引入 API Gateway 后:
|
Gateway 解决的核心问题:
| 关注点 | 没有 Gateway | 有 Gateway |
|---|---|---|
| 服务发现 | 客户端维护多个服务地址 | 客户端只知道 Gateway 一个入口 |
| 认证鉴权 | 每个服务各自实现 | Gateway 统一验证 token,内部通信信任 |
| 限流 | 每个服务各自实现 | Gateway 统一限流保护后端 |
| 协议转换 | 客户端必须用服务的协议 | 对外 REST,内部转 gRPC |
| API 聚合 | 客户端发 N 个请求拼数据 | Gateway 一次请求聚合多服务数据 |
| 安全隔离 | 内部服务暴露在公网 | 只有 Gateway 有公网入口 |
API Gateway = 酒店前台.
住客(客户端)不需要知道每个部门(服务)的内线号码,只需要拨前台,前台负责转接,验证身份,拦截骚扰电话(限流),翻译语言(协议转换).
Gateway 核心能力
路由(Routing)
根据 URL 路径,HTTP 方法,Header 等条件将请求分发到对应的后端服务:
|
认证与鉴权
Gateway 统一验证外部请求的身份(Authentication)和权限(Authorization):
AuthN 与 AuthZ:先证明你是谁,再决定你能干啥
- Authentication(AuthN,认证):你是谁?验证身份是否真实(authentic).失败返回 401.
- Authorization(AuthZ,授权):你能干啥?决定是否有权限访问.失败返回 403.
- 类比刷工卡进楼:刷卡证明"我是张三"(AuthN)→ 卡只能开 3 楼的门(AuthZ).先 N 后 Z,认证在前,授权在后.
- 客户端携带 JWT / OAuth2 token
- Gateway 验证 token 有效性(签名,过期时间)
- 将解析后的用户信息(user_id,roles)注入到 Header 中转发给后端
- 后端服务直接信任 Gateway 转发的 Header,无需重复验证
|
内部服务不要信任外部 Header
如果后端服务直接暴露给外部(绕过 Gateway),攻击者可以伪造 X-User-ID Header.
确保内部服务只接受来自 Gateway 的流量(通过网络策略 / mTLS / 内部 token).
限流(Rate Limiting)
防止单个客户端或突发流量打垮后端:
| 算法 | 特点 | 适用场景 |
|---|---|---|
| 固定窗口 | 每 N 秒允许 M 个请求 | 简单限流 |
| 滑动窗口 | 平滑计数,无窗口边界突刺 | 精确限流 |
| 令牌桶 | 允许一定突发,长期保持平均速率 | 允许短时突发(如 API 公共接口) |
| 漏桶 | 严格平滑输出速率 | 对下游保护要求高 |
限流维度:
- 按 IP(防爬虫)
- 按 User ID(按用户配额)
- 按 API Key(按租户/套餐计费)
- 按路由(热点接口单独限流)
协议转换
对外暴露 RESTful JSON,内部转发为 gRPC:
|
实现方式:
- gRPC-Gateway:从 .proto 文件自动生成 REST 反向代理(上一篇讲过)
- Envoy gRPC-JSON transcoding:配置级转换,无需代码
- 手写 BFF 层:复杂聚合场景下的定制方案
请求聚合
移动端一个页面可能需要 5 个服务的数据.没有聚合时要发 5 个请求(高延迟,高流量消耗).Gateway 可以合并为一次请求:
|
BFF 模式(Backend for Frontend)
不同客户端的需求差异很大:
- Web:大屏幕,可以展示详细信息,带宽不敏感
- iOS/Android:小屏幕,需要精简数据,带宽敏感
- 小程序:功能子集,API 更简单
- 第三方开放 API:标准 REST,版本稳定
用一个 Gateway 服务所有客户端会导致:接口越来越臃肿(为了兼容所有端),改动互相影响,无法按端独立发布.
BFF 架构
|
每个 BFF 的职责:
- 为特定客户端裁剪和聚合 后端数据
- 做协议转换(REST → gRPC)
- 由对应的前端团队拥有和维护
- 可以独立部署和演进
BFF 的所有权
BFF 应该由前端/客户端团队拥有,而非后端团队.
因为 BFF 的变更动机来自 UI 需求--"首页要加个推荐位"不应该让后端团队改代码.这也是 BFF 能加速交付的核心原因.
BFF vs 通用 Gateway
| 通用 API Gateway | BFF | |
|---|---|---|
| 职责 | 路由,认证,限流(横切关注点) | 数据聚合,裁剪,适配(业务逻辑) |
| 数量 | 通常 1 个(或按域分几个) | 每种客户端一个 |
| 包含业务逻辑 | 不应该 | 轻量业务逻辑(聚合,转换) |
| 维护者 | 平台团队 | 对应客户端团队 |
实践中两者常共存:Gateway(横切)→ BFF(聚合)→ 后端微服务.
主流 Gateway 方案对比
| 方案 | 语言/生态 | 特点 | 适用场景 |
|---|---|---|---|
| Kong | Lua + Nginx | 插件丰富,社区大,企业版付费 | 通用 API 管理 |
| APISIX | Lua + Nginx | 国产开源,高性能,etcd 配置中心 | 国内团队首选 |
| Envoy | C++ | 云原生标配,xDS 动态配置,Istio 数据面 | Service Mesh,K8s 原生 |
| Traefik | Go | 自动服务发现(K8s/Docker),配置简单 | 中小团队,K8s 原生 |
| 自研 BFF | Go/Node.js | 完全可控,聚合逻辑灵活 | 复杂聚合需求 |
选型建议
K8s 环境:Ingress Controller(Nginx/Traefik)处理基础路由 + APISIX/Kong 处理 API 管理(认证/限流/监控),或直接用 Istio Gateway.
需要 BFF:用 Go 自研轻量 BFF 服务(可以用 connect-go 或 gin),聚合后端 gRPC 服务.
不要把 Gateway 和 BFF 混为一谈--Gateway 是基础设施,BFF 是业务层.
Gateway 反模式
反模式一:胖 Gateway
把业务逻辑塞进 Gateway:数据校验,业务规则,数据库查询...Gateway 变成了新的单体.
正确做法:Gateway 只做横切关注点(路由/认证/限流/监控).需要业务逻辑的聚合放 BFF 层.
反模式二:单点 Gateway
Gateway 是所有流量的入口--它挂了整个系统都不可用.
正确做法:
- 多实例部署 + 负载均衡(至少 2 个副本)
- 无状态设计(状态放 Redis / 外部存储)
- 健康检查 + 自动故障转移
- 限流保护 Gateway 自身不被打垮
反模式三:Gateway 感知服务内部
Gateway 路由配置与后端服务的内部路径强绑定.服务重构就要改 Gateway 配置.
正确做法:Gateway 按域路由到服务根路径,服务内部路由由服务自己管理.
Gateway 安全实践
- TLS 终止:Gateway 处理 HTTPS,内部通信可以用 mTLS 或明文(配合网络策略隔离)
- CORS 处理:在 Gateway 统一配置跨域策略,后端服务不需要关心
- 请求大小限制:防止大 payload 攻击(body size limit)
- 请求头清洗:删除客户端注入的内部 Header(如 X-User-ID),防止伪造
- API 版本管理:通过路径前缀(/v1/,/v2/)或 Header 实现版本路由
Gateway 可观测性
Gateway 是流量入口,天然是最佳的观测点:
| 指标 | 含义 | 告警阈值参考 |
|---|---|---|
| 请求量 QPS | 流量趋势,峰值识别 | 突增 3 倍触发告警 |
| 延迟 P50/P99 | 用户体感 | P99 > 1s 告警 |
| 错误率 4xx/5xx | 服务健康度 | 5xx > 1% 告警 |
| 限流触发次数 | 是否需要扩容 | 持续触发说明容量不足 |
| 上游响应时间 | 定位慢服务 | 按路由分组看哪个后端慢 |
Access Log 是排障的第一手资料
Gateway 的 access log 应包含:请求时间,客户端 IP,方法,路径,状态码,响应时间,上游服务,trace_id.
遇到问题时,从 Gateway 日志入手定位"哪个服务,哪个接口,什么时候开始慢/错"远比猜测高效.
与 K8s Ingress 的关系
在 Kubernetes 04-05 篇中讲过 Ingress 和 Gateway API.它们和 API Gateway 的关系:
| K8s Ingress / Gateway API | API Gateway(Kong/APISIX) | |
|---|---|---|
| 层次 | 基础设施层(流量入口) | 应用层(API 管理) |
| 核心功能 | 路由 + TLS + 基础限流 | 认证 + 限流 + 监控 + 转换 + 插件 |
| 配置方式 | K8s YAML(Ingress/HTTPRoute) | 自有配置系统或 K8s CRD |
| 灵活度 | 中等 | 高(丰富的插件生态) |
常见组合:
- 简单场景:Nginx Ingress Controller 直接当 Gateway 用(路由 + TLS + 基础限流)
- 中等场景:Traefik / APISIX 作为 Ingress Controller + API Gateway 一体化
- 复杂场景:外层 LB → API Gateway(认证/限流/监控)→ 内部 Service Mesh(Istio)
快速回顾
- API Gateway:外部流量唯一入口,负责路由,认证,限流,协议转换等横切关注点
- BFF:为特定客户端量身聚合/裁剪数据,由对应前端团队拥有
- Gateway 不做业务逻辑--业务聚合放 BFF 层
- 协议转换:对外 REST JSON,内部 gRPC(gRPC-Gateway / Envoy transcoding)
- 限流算法:令牌桶(允许突发)最通用
- 多实例无状态部署防止 Gateway 成为单点故障
- 可观测性:Gateway 是最佳观测点(QPS / 延迟 / 错误率 / 上游时间)
动手练习
- 启动 Gateway 配路由:用 Docker 启动 APISIX 或 Traefik,配置两条路由分别指向两个后端服务(可以用 httpbin 做 mock)
- 压测验证限流:给其中一条路由配置限流(每秒 10 个请求),用
hey或ab压测验证限流生效 - 实现 BFF 聚合服务:实现一个简单的 Go BFF 服务:接受一个
GET /homepage请求,并行调用两个后端 gRPC 服务,聚合后返回 JSON - 配置 JWT 认证:Gateway 验证 token 并注入 X-User-ID,后端服务读取该 Header