服务网格:从 sidecar 到 Ambient,那笔"分布式税"怎么省

写在前面

《每个程序员都该知道的延迟数字》里点过一笔账:Service Mesh 代理会增加延迟和资源消耗,但开销不是一个跨环境固定的“每跳毫秒数”。Istio 官方基准显示,它会随协议、连接数、请求率、负载大小、代理线程数和遥测功能明显变化。《后端架构实战(四):微服务的"分布式税"》讲过这笔税为什么存在。

这篇比较三种数据面路线:sidecar、Istio Ambient,以及以 eBPF 加速网络路径的 Cilium Service Mesh。它们不是严格接替的“三代产品”,而是可以并存的架构选择。

这篇是独立参考稿,不绑某个系列。它和《分布式税》《延迟数字》《Polly》《可观测性》几篇互相印证,串成"微服务通信"的一条线。


一、服务网格到底解决什么

微服务一起来,每一条 service-to-service 链路都背着同一堆非功能性需求

  • 安全:双向加密 + 身份认证(mTLS)——别让内网裸奔;
  • 弹性:超时、重试、熔断、限流——别让一个慢下游拖垮整条链路;
  • 流量治理:金丝雀发布、按比例分流、按 header 路由、流量镜像;
  • 可观测:服务间拓扑、延迟分布、错误率、访问日志。

每个服务自己用框架(.NET 的 Polly、Java 的 Resilience4j、Go 的中间件……)实现一遍 = 语言不一致、版本不一致、改一条策略要动几十个仓库

服务网格做的事就一句话:把这一整层从应用代码里抽出来,下沉成独立的基础设施层。应用只管业务逻辑,网格管"服务间通信的所有非功能性需求"。

所以网格不是"替你交分布式税",而是让交税的方式标准化、集中化——税还在,但不再每个服务各交各的。


二、第一代:Sidecar(Istio + Envoy)

怎么工作

每个 Pod 被 mutating webhook 注入一个 Envoy sidecar,Pod 内所有进出流量被 iptables 规则重定向到本地 Envoy。应用完全无感——它以为自己直连对端,其实流量先被本地 Envoy 拦了一道。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Pod A                            Pod B
┌────────────────┐               ┌────────────────┐
│   App          │               │   App          │
│    │           │               │    ▲           │
│    ▼           │               │    │           │
│   Envoy ───────┼──── mTLS ────→┼── Envoy        │   ← 每 Pod 一个 sidecar
└────────────────┘               └────────────────┘

一次调用: app → 本地 Envoy → 网络 → 对端 Envoy → 对端 app
        多了 2 个本地代理跳 + 2 次 mTLS 加解密

能力与代价

能力(这一代把网格能做的几乎全做到了):mTLS + SPIFFE 身份、VirtualService 的金丝雀/分流/镜像、DestinationRule 的熔断/outlier detection、全量遥测(指标/链路/访问日志自动埋点)。

代价正是延迟篇那笔账:

  • 延迟:请求多经过客户端和服务端代理,过滤器、遥测和排队都会增加平均与尾部延迟;实际值必须按自己的协议、并发和策略压测。
  • 资源:每个工作负载都有代理。Istio 1.24 的官方参考测试中,1 KB 请求、1000 RPS、两个 worker 的单个 sidecar 约占 0.20 vCPU 和 60 MB 内存;这只是特定基准,不是容量规划常数。
  • 启动:Pod 启动变慢且有序问题——应用先于 Envoy 就绪时,出站连接失败;Envoy 先于应用时,入站没人接。

sidecar 模型的问题不在"能力不够",而在粒度太细:每个 Pod 都扛一个全功能 Envoy,绝大多数流量其实只用到它 mTLS 这一小块。


三、第二代:Ambient(ztunnel + waypoint)

核心思路:L4 和 L7 解耦

Istio Ambient 的洞察是——大多数流量只需要 mTLS(L4),不该每个 Pod 扛一个全功能 Envoy。于是把数据面拆成两层:

  • ztunnel:每台 node 跑一个(DaemonSet),用 Rust 写的极轻 L4 代理。只管 mTLS 加解密 + L4 授权。node 上所有 Pod 的流量统一由它过,传输用 HBONE(HTTP/2 CONNECT 隧道协议)封装。
  • waypoint按需部署(per namespace 或 per service),本质还是 Envoy,但只在需要 L7 策略时才起(流量分割、HTTP 级重试、L7 授权)。不需要 L7 的服务,流量只过 ztunnel,不碰 waypoint。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Node 1                            Node 2
┌─────────────────────┐           ┌─────────────────────┐
│  Pod A    Pod B     │           │  Pod C    Pod D     │
│    │        │       │           │    │        │       │
│    ▼        ▼       │           │    ▲        ▲       │
│    └──→ ztunnel ────┼── HBONE ──┼→ ztunnel ←──┘       │  ← 每 node 一个(L4)
│          (L4)       │   隧道    │      (L4)           │
│            │        │           │       │ (按需)      │
│            ▼        │           │       ▼             │
│        waypoint     │           │   waypoint          │  ← 需要 L7 才起
└─────────────────────┘           └─────────────────────┘

L4 流量只过 ztunnel(轻);要 L7 治理才加 waypoint 那一跳

收益与代价

收益

  • 减少重复资源:从“每工作负载一个 Envoy”变成“每节点一个轻量 ztunnel + 按需 waypoint”;能省多少取决于 Pod、节点、waypoint 副本数和策略规模。
  • 避免 per-Pod 代理:流量仍会经过源、目的节点上的 ztunnel,HBONE 也仍有代理、加密与排队成本;收益来自更轻的共享 L4 数据面,而不是“近乎零额外跳”。
  • 零侵入:业务 Pod 不再被注入 sidecar,迁移成本和故障面都小。
  • 可并存:Ambient 能和 sidecar 模式混跑,逐服务渐进迁移。

代价

  • 心智更绕:ztunnel + waypoint + HBONE 三件事,比"一个 sidecar"复杂。
  • L7 那一跳省不掉:要流量分割/重试,waypoint 本质还是个 Envoy——只是换了部署位置。
  • 能力仍在演进:Ambient 于 2024 年 5 月随 Istio 1.22 进入 Beta,并于 2024 年 11 月随 1.24 达到 GA;核心 ztunnel、waypoint 和 API 已标记 Stable,但与 sidecar 的功能对齐仍是后续路线图的一部分。

四、另一条路线:eBPF(Cilium Service Mesh)

核心思路:既然要离开应用进程,干脆离开用户态

Cilium 使用 eBPF 在内核数据路径中完成服务负载均衡、网络策略和可观测等 L3/L4 工作;需要解析 HTTP、gRPC、Kafka 或 DNS 等应用层协议时,流量仍要重定向到用户态 Envoy。

  • L3/L4:eBPF 负责转发、负载均衡、策略执行和观测;可选的 WireGuard/IPsec 提供透明加密,但这不等同于成熟的工作负载级 mTLS 身份认证。
  • 身份认证:Cilium 的 SPIFFE/SPIRE mutual authentication 在当前文档中仍为 Beta,若要同时获得加密,还需启用 WireGuard 或 IPsec。
  • L7:eBPF 将需要应用层处理的流量透明重定向到 Envoy;具体部署形态取决于安装配置。

一个必须说清的诚实点

Cilium 经常被宣传成"无 sidecar、eBPF 搞定一切",但它的 L7 仍然要靠 Envoy,只不过从"每 Pod 一个"换成了"每 node 一个共享实例"。所以:

Cilium 和 Ambient 都不是“消灭所有代理”。Ambient 用节点级 ztunnel 承担安全 L4 overlay,并按需加入 waypoint;Cilium 用 eBPF 承担大量 L3/L4 工作,但 L7 仍依赖 Envoy。二者的身份模型和策略 API 也不同。

收益与代价

收益:L3/L4 极致性能(内核原生)、无 per-pod 开销、内核级可观测(网络指标天然丰富)。

代价

  • L7 多租户隔离是社区讨论点——共享 node Envoy 处理多服务流量,隔离不如 per-pod sidecar 干净。
  • 依赖满足 Cilium 支持矩阵的 Linux 内核与功能配置;不要用一个笼统的 5.10+ 代替安装前的系统要求检查。
  • 控制面是 Cilium 自家体系CiliumNetworkPolicy 等 CRD),和 Istio 的 VirtualService/DestinationRule 不通用,迁移有成本。

五、三条路线横评

维度Sidecar(Istio 经典)Ambient(Istio)eBPF(Cilium)
数据面位置每 Pod 一个 Envoy每 node 一个 ztunnel + 按需 waypoint内核 eBPF(L3/L4)+ 每 node Envoy(L7)
L7 能力全(Envoy 原生)全(waypoint = Envoy)有,但弱于 Istio 的体系
每 Pod 开销大(几十~百 MB)几乎为零(无 sidecar)几乎为零(无 sidecar)
延迟开销多两个代理数据路径,需实测L4 路径更轻;L7 增加 waypointL3/L4 主要在 eBPF 路径;L7 增加 Envoy
心智复杂度中(最成熟、资料最多)中高(ztunnel + waypoint + HBONE)中(eBPF + 内核依赖)
成熟度最成熟Istio 1.24 起 GA;功能仍持续对齐Cilium 网络数据面成熟;mutual authentication 仍为 Beta
适用已有 Istio、重度 L7 治理新部署、求轻量、要 mTLS+可观测新内核、追性能、L7 需求不重

六、那笔税到底省了多少

回到延迟问题,更稳妥的比较方式是看数据路径,而不是套一个固定的“每 hop”数字:

1
2
3
sidecar(每工作负载 Envoy):请求经过两端 Envoy,功能完整、资源隔离清晰
Ambient L4(ztunnel + HBONE):请求经过两端节点 ztunnel,共享轻量 L4 数据面
Cilium L3/L4(eBPF):转发与策略主要在内核路径;需要 L7 时再进入 Envoy

(Ambient/Cilium 的精确延迟要看各自的官方基准,随负载和场景漂移;这里给的是相对量级。)

最该记住的洞察:这些路线不是把分布式通信变成零成本,而是在代理隔离、共享资源和内核加速之间取舍。只要需要基于 HTTP 等应用层语义做治理,就需要 L7 解析;在本文讨论的实现里,这仍由 Envoy 承担。

所以省下的是基础 mTLS 这一层的重复税,不是"L7 治理本身的税"。L4 需求为主、L7 需求少的服务,是 Ambient/Cilium 最大的受益者。


七、怎么选(决策清单)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
□ 已有 Istio + 重度 L7 治理(金丝雀/重试都写在 VirtualService 里)
   → 留 sidecar;想降开销就逐服务迁 Ambient(能并存,渐进)

□ 新部署、主要要 mTLS + 基础可观测、资源敏感
   → Ambient

□ Linux 内核满足目标 Cilium 版本的系统要求、重视网络数据面效率、团队熟悉 eBPF
   → Cilium

□ 规模没到(几十个服务以下)
   → 可能根本不需要网格

最后一条最容易踩坑。网格自身的运维复杂度(控制面、版本升级、故障排查、CRD 体系)不低。规模没到时,可以按需求组合网络策略、平台提供的工作负载身份或 mTLS 能力、应用侧 Polly 与 OpenTelemetry;其中 Kubernetes NetworkPolicy 只做网络访问控制,本身不提供 mTLS。网格是规模问题的解药,不是小集群的补品。


八、和 .NET / ASP.NET Core 的分工

网格下沉之后,应用层还做什么?关键原则是别重叠——两边都做同一件事,不仅浪费,还会出事:

  • mTLS:若网格已覆盖这条链路,应用通常不必再重复建立一层同目的的传输加密;但端到端合规边界、网格外流量和应用层加密需求仍需单独评估。
  • 重试 / 超时 / 熔断二选一。要么网格(Istio 的 DestinationRule / Ambient waypoint),要么应用(Polly)。两边都开 = 双重重试,一个失败触发两层的重试风暴,放大流量、恶化雪崩——这是最常见的坑。一般原则:跨服务边界的通用策略 → 网格;和业务逻辑绑定的(“这个 API 失败重试 3 次且只对特定错误”)→ 应用层 Polly。详见《Polly 的前世今生》《分布式税》。
  • 可观测互补,不是替代。网格给"服务间拓扑 + 调用延迟 + 错误率"(数据面自动埋点,零侵入);OpenTelemetry 给"业务全链路 + 应用内 span"。两者通过 trace context 串联,画面才完整。详见《后端架构实战(七):可观测性》。
  • 流量治理(金丝雀、AB、按 header 分流):网格擅长,别在应用里自己造路由层。

小结

  • 服务网格 = 把服务间通信的非功能性需求(mTLS / 弹性 / 治理 / 可观测)从应用下沉成独立基础设施层。
  • 三条路线:sidecar(每工作负载 Envoy)、Ambient(节点级 ztunnel + 按需 waypoint)、Cilium(eBPF L3/L4 + 按需 Envoy L7);它们并非严格代际替换。
  • 税省了什么:Ambient 和 Cilium 都避免 per-Pod sidecar,但数据路径、身份认证与 L7 处理仍有成本;必须以目标环境的 p50/p99、吞吐和资源占用实测选型。
  • 选型:看 L7 需求 / 规模 / 内核版本 / 团队能力;规模没到别硬上,Polly + OTel 可能更划算。
  • 和应用层的边界:mTLS 交网格、重试别两边都开(双重重试是最常见的坑)、可观测互补。

一句话:服务网格这十年的故事,就是把"分布式税"从每个应用进程里,一寸一寸挪到 node 和内核——挪得越远,应用越轻,但那笔 L7 的核心税,到现在谁也没真消掉。


参考资料