把单体拆成微服务,一个新问题就冒出来:每个服务现在都需要同一套枯燥但关键的机制——认证、限流、TLS、路由、重试、监控指标。在每个服务里重复实现既浪费又不一致。两个模式把它抽到基础设施里:API 网关处理从客户端进入系统的流量,服务网格处理服务之间的流量。两者合起来让你的服务代码专注于业务逻辑。
- 两者都解决横切关注点——认证、限流、TLS、路由、重试、可观测性——这样单个服务不必各自重造。
- API 网关 = 前门——客户端的单一入口,把请求路由到后端服务,并处理认证、限流、TLS 终结和聚合。
- 南北向 vs 东西向——网关管客户端↔系统(南北向)流量;网格管服务↔服务(东西向)流量。
- 服务网格 = 每服务一个 sidecar 代理——透明地给内部调用加上 mTLS、重试、负载均衡和指标,由控制平面统一配置所有代理。
- BFF(Backend for Frontend)——为每种客户端(Web、移动)定制的网关,塑形响应。
- 代价是多一跳 + 复杂度——网格尤其会增加延迟和运维负担;别在真正需要前就上。
API 网关是外部客户端的单一入口:它把请求路由到服务,并集中处理认证、限流、TLS 终结和请求聚合(南北向流量)。服务网格把服务间关注点(mTLS、重试、负载均衡、追踪)下推到部署在每个服务旁边的 sidecar 代理里,由控制平面配置(东西向流量)。两者都把横切逻辑从应用代码里抽出来——代价是多一次网络跳转和运维复杂度。
问题:横切关注点
在微服务架构里,有一组关注点适用于每个服务:验证调用方是谁(认证/鉴权)、限制滥用流量、终结 TLS、路由请求、重试瞬时失败、发出指标/追踪。如果每个团队都把这些烤进自己的服务,你会得到重复劳动,以及——更糟——不一致:十个略有差异的限流器、五种认证实现、参差不齐的可观测性。解法是把这些关注点提升到一个共享层。放在哪取决于流量的方向。
南北向 vs 东西向流量
来自网络的一个有用心智模型:
- 南北向流量跨越你系统的边界——外部客户端打进来(以及响应出去)。API 网关坐在这里,在边缘。
- 东西向流量在你的内部服务之间流动。服务网格管这个。
网关是把守的前门;网格是内部的道路网。它们互补,不竞争。
API 网关
API 网关是坐在你后端服务前面的单一入口。客户端只和网关说话,网关认证并把每个请求路由到正确的服务,并施加边缘策略。它的职责:
- 路由——把进入的路径/主机映射到后端服务。
- 认证与鉴权——在边缘一次性校验 token/key(常用 OAuth/JWT),这样服务信任网关。
- 限流与节流——保护后端免于滥用和过载。
- TLS 终结——在边缘处理 HTTPS。
- 请求聚合——把对多个服务的调用合并成一个客户端响应(减少移动端的碎片往返)。
- 协议转换——如对外暴露 REST,对内说 gRPC。
客户端 ─▶ ┌─────────────── API 网关 ─────────────────┐
│ TLS 终结 · 认证 · 限流 · 路由 │
└───┬──────────────┬──────────────┬─────────┘
▼ ▼ ▼
order-svc user-svc payment-svc
(服务信任网关;它们不必各自重新认证客户端)
BFF 模式
一个 Web 应用、一个移动应用、一个合作方 API,常常想要同一批后端数据的不同形状。Backend for Frontend(BFF) 模式为每种客户端跑一个独立的网关,各自把聚合和响应塑形裁剪到该客户端的需要——所以移动 BFF 可以返回紧凑、省电的载荷,而 Web BFF 返回更丰富的,而不必把后端服务撑胖。
服务网格
网关管边缘,但在一个大系统内部,服务之间不停互相调用,这些调用需要同样的可靠性和安全特性。服务网格提供它们,而不改应用代码,用的是 sidecar 模式:在每个服务实例旁边部署一个小代理(如 Envoy),该服务的所有网络流量都流经它的 sidecar。这些 sidecar(数据平面)由一个控制平面(如 Istio、Linkerd)集中配置。
┌── 控制平面(配置、策略、证书) ──┐
│ Istio / Linkerd │
▼ ▼
┌─ 服务 A ──┐ mTLS、重试、负载均衡、指标 ┌─ 服务 B ──┐
│ app │代理 │◀═══════════════════════════▶│ 代理 │ app │
└─────┴─────┘ (A↔B 全部流量经 sidecar) └─────┴─────┘
app 代码只是普通调用 "B";sidecar 干其余的
因为每次调用都过 sidecar,网格透明地提供:双向 TLS(mTLS)(自动加密 + 认证服务间通信)、重试、超时、熔断、客户端负载均衡、流量切换(用于 金丝雀部署),以及统一的可观测性(每一跳都被追踪/度量——见可观测性)。应用对此毫无察觉;它只是调用"服务 B",sidecar 处理加密、重试和路由。
网关 vs 网格
| 方面 | API 网关 | 服务网格 |
|---|---|---|
| 流量 | 南北向(客户端 ↔ 系统) | 东西向(服务 ↔ 服务) |
| 形态 | 中心化的边缘服务 | 每服务一个 sidecar + 控制平面 |
| 主要职责 | 认证、限流、路由、聚合 | mTLS、重试、负载均衡、流量切换 |
| 面向客户端? | 是——外部客户端 | 否——仅内部 |
| 例子 | Kong、NGINX、AWS API Gateway | Istio、Linkerd(Envoy 数据平面) |
取舍与何时用哪个
两者都增加一次网络跳转和运维件,所以并不免费。一旦你有多个对客户端暴露的服务,API 网关几乎总是值得的——光是集中认证和限流就够理由(只是别让它变成一个塞满业务逻辑的臃肿单体;只放横切关注点)。服务网格更重:sidecar 给每次内部调用加延迟,控制平面是实打实的运维复杂度。它在规模上回报——几十个以上的服务、你想要统一的 mTLS、重试和可观测性而不去碰每个代码库时——但对少数几个服务就是过度设计,一个好网关加几个库就够了。诚实的面试答案:当跨多个服务的横切需求超过网格的运维成本时才上,而不是默认就上。
sidecar 的超能力——透明拦截所有流量——也是它的代价:每个请求现在要多穿两个代理(调用方的 sidecar → 被调方的 sidecar),增加延迟和 CPU。较新的"无 sidecar"/ambient 网格设计试图降低这个开销,但透明与多一跳之间的根本张力依然存在。
常见坑
- 网关变单体——把业务逻辑塞进网关又重造了你拆掉的那个单体;只放横切关注点。
- 网关成单点故障——它在所有流量的关键路径上;让它高可用并放在负载均衡器后面。
- 过早上网格——为五个服务上服务网格,增加的复杂度比它消除的还多。
- 对延迟无感——额外的跳(网关 + 两个 sidecar)会累加;度量它们引入的尾延迟。
API 网关和服务网格都把横切关注点从服务里抽出来——网关在南北向边缘(为外部客户端做认证、限流、路由、聚合),网格在东西向内部流量上(用 sidecar 做 mTLS、重试、负载均衡、可观测性)。早点上网关;只在服务多到让网格的统一性值回它的延迟和运维成本时,才上网格。
API 网关 vs 服务网格?网关处理南北向(客户端→系统)流量、作为中心化边缘;网格通过 sidecar 代理处理东西向(服务→服务)流量。
网关做什么?单一入口:路由、认证、限流、TLS 终结、请求聚合、协议转换。
什么是 sidecar 模式?部署在每个服务旁的代理,拦截它所有流量,在不改应用代码的情况下加上 mTLS/重试/负载均衡/指标;控制平面配置所有 sidecar。
什么是 BFF?为每种客户端(Web、移动)定制的网关,裁剪聚合和响应形状。
什么时候不该用网格?服务少时——sidecar 的每次调用延迟和运维开销盖过收益;一个网关加库就够了。