Service Mesh从零到生产级:Envoy、xDS、mTLS与流量治理原理
Service Mesh把服务间通信中的一部分通用能力从业务SDK下沉到代理和控制面:服务发现、四层/七层路由、mTLS、重试、超时、熔断、异常实例剔除和遥测。它解决的是“服务怎样安全、可观测、可治理地互相通信”,并不替代业务幂等、数据库事务、消息最终一致、用户权限或领域错误处理。
本页以Envoy和Istio常见模型解释原理,同时标明Consul Connect、Linkerd和Sidecar/Ambient形态的边界。产品字段随版本演进,生产配置必须以目标版本文档和实际代理配置为准;这里讲的是稳定的对象关系和失败模型。
学完本页后继续进入 Service Mesh 内部原理与生产治理:从 Envoy Worker、Listener Filter、HCM、Route、Cluster、Endpoint 和连接池一路追到 xDS 双向流、Warming、Panic Mode、Outlier Detection、SDS、Ambient、商业配置 Demo 与逐层 Runbook。面试标准回答单独放在 Service Mesh 独立面试题。
一、学习目标
学完后应能:
- 区分Mesh控制面与数据面,解释控制面异常时已有流量为什么可能继续。
- 解释Envoy Listener、FilterChain、Route、Cluster、Endpoint和Secret的关系。
- 解释LDS、RDS、CDS、EDS、SDS分别下发什么。
- 说清xDS的版本、nonce、ACK、NACK和Last Known Good配置。
- 画出Sidecar出站、入站和mTLS完整调用链。
- 解释工作负载身份、证书签发、轮换、信任域和授权边界。
- 区分连接超时、请求超时、每次尝试超时、总Deadline和空闲超时。
- 解释重试乘法、熔断、异常实例剔除、局部性路由和灰度发布。
- 区分Sidecar、Ambient、Spring Cloud SDK和API Gateway的职责。
- 按503 NR/UH/UF、xDS NACK、mTLS失败和配置陈旧执行Runbook。
二、Mesh解决什么,不解决什么
| 能力 | Mesh可以做什么 | 仍由业务负责什么 |
|---|---|---|
| 服务发现 | 把平台端点转换为代理可用后端 | 业务服务身份和版本契约 |
| 路由 | 按Host、Header、权重、路径分流 | 灰度数据兼容和回滚决策 |
| mTLS | 工作负载双向认证和链路加密 | 用户认证、字段加密、业务授权 |
| 重试 | 对选定失败类型执行有界重试 | 幂等键、结果查询、补偿 |
| 超时 | 在代理层终止过慢调用 | 业务Deadline传播和取消语义 |
| 熔断 | 限制连接、请求、Pending和重试 | 容量规划和业务降级结果 |
| 遥测 | 记录代理看到的流量、延迟和状态 | 业务事件、订单号和领域结果 |
不使用Mesh也可以做微服务;使用Mesh也不会自动得到“Exactly Once”。代理看到上游超时,不知道下游数据库是否已经提交。涉及支付、库存和退款时,调用方仍需稳定业务号、幂等和事实查询。
三、控制面与数据面
flowchart TD
A["Kubernetes Service与EndpointSlice"] --> B["Mesh控制面构建期望配置"]
C["路由、安全与授权策略"] --> B
B --> D["通过xDS下发给代理"]
D --> E["调用方数据面代理"]
D --> F["服务方数据面代理"]
E --> G["真实业务请求不经过控制面"]
G --> F
F --> H["业务容器"]3.1 控制面
控制面观察服务注册、端点、配置和安全策略,计算每个代理应该看到的监听器、路由、集群、端点和证书。它是配置分发者,不应位于每次业务请求的数据路径中。
3.2 数据面
数据面代理实际接收、建立连接、路由、加密、重试和记录指标。Sidecar模式通常每个Pod一个代理;其他模式可能在节点或专用网关中承担部分能力。
3.3 为什么控制面挂了流量可能继续
代理通常保留已经接受的Last Known Good配置。控制面短暂不可用时:
- 已有Listener、Route、Cluster和Endpoint仍能处理流量。
- 已建立连接可以继续使用。
- 新服务、新端点、路由变更和证书轮换可能无法及时生效。
- 配置过旧、证书到期或端点全部变化后,数据面仍会逐渐失效。
所以“控制面挂了业务完全没事”与“控制面挂了所有流量立刻断”都不准确。答案取决于缓存配置、证书剩余时间、端点变化和代理重启。
四、Envoy核心对象
| 对象 | 作用 | 可类比理解 |
|---|---|---|
| Listener | 监听地址和端口,接收进入代理的连接 | 入口插座 |
| FilterChain | 按传输协议、SNI等选择一组处理链 | 入口分流规则 |
| Network Filter | 处理TCP层协议 | 四层处理器 |
| HTTP Connection Manager | 解析HTTP并承载HTTP过滤器和路由 | 七层总入口 |
| Route Configuration | 按域名、路径、Header匹配目标Cluster | 路由表 |
| Cluster | 一个逻辑上游服务及连接、LB、健康配置 | 服务目标 |
| Endpoint | Cluster中的实际IP、端口、优先级和地域 | 服务实例 |
| Secret | TLS证书、私钥和信任根等 | 动态安全材料 |
一次HTTP出站调用的对象关系:
flowchart TD
A["连接进入Outbound Listener"] --> B["FilterChain选择协议处理"]
B --> C["HTTP Connection Manager解析请求"]
C --> D["VirtualHost与Route匹配"]
D --> E["Route选择目标Cluster"]
E --> F["Load Balancer选择Endpoint"]
F --> G["连接池取得或建立上游连接"]
G --> H["TLS过滤器执行mTLS"]
H --> I["请求发送到服务方代理"]常见误区是把Cluster等同于一个IP。Cluster是逻辑目标,内部有多个Endpoint、连接池、健康和负载策略。路由先选Cluster,负载均衡再从Cluster中选Endpoint。
五、xDS:控制面怎样把配置交给Envoy
xDS是动态配置API族,不是单个“注册中心协议”。常见资源:
| API | 下发内容 | 缺失或错误的表现 |
|---|---|---|
| LDS | Listener和FilterChain | 端口未监听、入站/出站无法接收 |
| RDS | HTTP Route、VirtualHost、匹配规则 | 404或NR,流量到错版本 |
| CDS | 上游Cluster、连接和LB策略 | 找不到目标Cluster |
| EDS | Cluster的Endpoint和局部性信息 | UH、无健康后端、旧地址 |
| SDS | 证书、私钥、信任根 | TLS握手失败或证书过期 |
有些配置可内联在其他资源中,产品也可能使用聚合发现服务统一承载多个资源流。理解重点不是背缩写,而是明确“监听、路由、逻辑服务、实例、安全材料”是不同生命周期的资源。
六、一次xDS配置更新完整过程
flowchart TD
A["平台端点或策略发生变化"] --> B["控制面计算代理目标配置"]
B --> C["xDS响应携带资源、version与nonce"]
C --> D["代理解析并做语义校验"]
D --> E{"配置是否可接受"}
E -- "是" --> F["原子发布新配置并ACK"]
E -- "否" --> G["保留Last Known Good并NACK"]
F --> H["后续新流量使用新快照"]
G --> I["控制面记录错误并修正"]6.1 version与nonce不是同一个概念
version_info用于标识控制面所表达的资源版本或快照版本。response_nonce标识某次具体响应,代理在下一次请求中回显,便于控制面关联ACK/NACK。- NACK通常会携带错误详情,表示代理未接受那次响应。
- ACK表示代理接受配置,不等于真实业务一定成功,也不等于所有代理都已ACK。
控制面不能只看“配置对象已保存”,还要观察目标代理的下发状态、ACK/NACK、版本分布和收敛时间。
6.2 State of the World与Delta
State of the World响应通常表达某类资源的完整目标集合,客户端按整体快照更新;Delta xDS按资源增删变化传递并维护订阅状态。两者的协议字段和恢复方式不同,但工程目标相同:代理必须从有版本的资源流收敛到一致、可验证的本地配置。
不要自己拼接半份Route或Endpoint直接覆盖生产代理。资源之间有依赖顺序,例如Route引用的Cluster必须存在,Cluster使用的Secret必须可用。成熟控制面需要依赖分析、增量推送、回滚和状态观测。
6.3 ACK不等于全局生效
一次发布可能处于这些状态:
- 配置已写入控制面存储。
- 控制面已计算目标代理配置。
- 一部分代理收到响应。
- 一部分ACK,一部分NACK或断连。
- ACK代理开始处理新连接,旧连接仍按旧路由或旧TLS会话存在。
因此灰度平台应按代理和工作负载统计配置版本,不应在“API返回200”后立即认为全网切换完成。
七、Sidecar流量怎样进入代理
Sidecar模式常通过Pod网络命名空间中的iptables或eBPF规则透明拦截流量:
- 出站:业务容器连接目标地址,规则重定向到本地出站Listener。
- 入站:进入Pod端口的连接先被重定向到入站Listener,再转发给业务容器。
- 排除:代理自身UID、健康检查端口、控制面地址等必须避免循环拦截。
flowchart TD
A["调用方业务容器发起请求"] --> B["Pod重定向规则捕获出站连接"]
B --> C["调用方Sidecar匹配Route和Cluster"]
C --> D["选择Endpoint并建立mTLS连接"]
D --> E["服务方Sidecar接受并校验身份"]
E --> F["入站授权和遥测过滤器"]
F --> G["转发到服务方业务容器"]透明拦截不是魔法:
- UDP、原始Socket、HostNetwork和特殊协议可能有额外边界。
- 应用自己发起TLS时,代理能否做L7路由取决于是否终止或理解该连接。
- 端口协议识别错误会让HTTP治理退化为TCP或解析失败。
- 排除规则错误可能形成代理自连接循环。
八、mTLS与工作负载身份
普通单向TLS主要让客户端验证服务端;mTLS还让服务端验证客户端证书。Mesh通常为工作负载颁发短期身份凭据,由代理完成握手。
flowchart TD
A["工作负载获得平台身份"] --> B["CA验证身份并签发短期证书"]
B --> C["SDS把证书和信任根交给代理"]
C --> D["调用方代理发起TLS握手"]
D --> E["双方验证证书链、身份和有效期"]
E --> F["协商会话密钥并加密传输"]
F --> G["服务方按来源身份执行授权策略"]8.1 身份不是Pod IP
Pod IP会变化,不能作为稳定身份。Mesh身份通常绑定命名空间、ServiceAccount或工作负载标识,并编码到证书SAN中。授权策略应判断经过验证的身份,而不是只信任请求Header中由调用者随意填写的用户名。
8.2 证书生命周期
- 工作负载启动并证明平台身份。
- CA或身份服务签发短期证书。
- SDS等机制把证书交给代理,避免业务代码直接管理私钥。
- 到期前主动轮换,新旧材料可在有限窗口重叠。
- 代理新连接使用新证书,已有TLS连接可能继续到关闭。
轮换失败不会一定立即中断;通常要等证书到期或新连接建立才暴露。必须监控证书剩余时间、SDS推送和握手错误。
8.3 STRICT、PERMISSIVE与迁移窗口
- STRICT:入站只接受符合Mesh mTLS要求的连接。
- PERMISSIVE:迁移阶段可能同时接受明文和mTLS。
- DISABLE或明文策略:只应在明确边界使用。
PERMISSIVE便于渐进迁移,但扩大明文窗口;STRICT过早启用会让未注入Sidecar、旧VM或探针调用失败。应先清点调用方、观察遥测、灰度策略,再收紧。
8.4 mTLS不等于业务授权
mTLS回答“哪个工作负载建立了连接”,不能回答“这个用户能否退款1000元”。服务间授权可按工作负载身份限制调用关系;用户权限、订单归属、字段级权限仍由业务认证授权处理。
九、一次Mesh HTTP调用全过程
- 业务线程根据Service DNS或原地址发起请求。
- 出站重定向规则把连接交给调用方代理。
- Listener和FilterChain识别端口、协议和TLS模式。
- HTTP Connection Manager解析Host、Path和Header。
- Route匹配目标Cluster,并计算超时、重试、Header改写和权重。
- Cluster负载均衡从当前健康Endpoint快照选择目标。
- 连接池复用或建立到服务方代理的连接。
- 双方代理执行mTLS并验证证书链和工作负载身份。
- 服务方代理执行入站授权、限流或遥测过滤器。
- 请求转发给业务容器,业务线程访问数据库并产生结果。
- 响应沿代理链返回,各层记录状态码、延迟和字节数。
- 若触发可重试条件,调用方代理在总预算内选择另一个Endpoint再尝试。
代理重试发生在第12步时,第一次请求可能已经提交数据库但响应丢失。因此支付创建、库存扣减等写接口必须使用幂等键,不能依赖“Mesh只会在安全情况下重试”的想象。
十、超时与Deadline为什么必须分层
| 超时 | 约束对象 | 配置过大后果 | 配置过小后果 |
|---|---|---|---|
| Connect timeout | 建立上游连接 | 故障地址拖住资源 | 网络稍慢即失败 |
| Per-try timeout | 单次尝试 | 第一次耗尽总预算 | 慢请求被过早放弃 |
| Request timeout | 代理处理整个请求 | 在途请求长期占用 | 合法长操作被截断 |
| Idle timeout | 连接或流空闲 | 僵尸连接长期存在 | 正常长连接频繁断开 |
| 应用业务Deadline | 端到端业务剩余时间 | 下游做无效工作 | 无法完成业务最小步骤 |
正确关系通常是:调用方总Deadline大于单次尝试时间,但小于上游允许等待时间;每次向下游传播“剩余预算”,而不是每层重新获得完整10秒。
假设网关10秒、订单服务10秒、库存服务10秒、数据库10秒,最坏不是10秒,而可能层层耗尽并让上游早已放弃后下游仍继续工作。生产要使用端到端Deadline并预留序列化、排队和响应返回时间。
十一、重试、重试乘法与结果未知
flowchart TD
A["一次用户请求"] --> B["网关最多2次尝试"]
B --> C["Sidecar每次最多2次尝试"]
C --> D["HTTP客户端每次最多3次尝试"]
D --> E["最坏可能形成12次下游尝试"]
E --> F["下游故障被重试流量进一步压垮"]重试设计必须同时满足:
- 明确可重试错误:连接前失败、特定网关错误等。
- 请求具备幂等语义或稳定幂等键。
- 有总Deadline、最大次数、退避和抖动。
- 有全链路重试预算,避免每层独立放大。
- 观察Attempt数量,而不只看用户请求数。
- 下游过载时优先快速失败,而不是继续重试。
HTTP GET也不天然安全:如果接口错误地在GET中产生副作用,代理无法替业务修正。POST也可以在业务幂等协议保护下安全重试。
十二、负载均衡、局部性与慢启动
常见策略包括Round Robin、Least Request、Random、Ring Hash或Maglev等一致性选择。选型取决于请求耗时分布、连接模型、会话亲和和扩缩容频率。
- Round Robin简单,但不感知某Pod上已有大量慢请求。
- Least Request倾向当前较空闲实例,但指标和采样有滞后。
- 一致性哈希可提高同Key命中同实例概率,却会形成热点且成员变化会迁移Key。
- Locality优先可减少跨区成本,但本区容量不足时需要受控溢出。
- 新Pod需要Warmup或Slow Start,避免刚Ready就承接等比例大流量。
Mesh LB通常基于代理当前EDS快照和本地统计,不是全局精确调度器。每个调用方代理可能做出不同选择。
十三、熔断、并发限制与异常实例剔除
13.1 Envoy语境中的Circuit Breaking
Envoy Cluster的熔断阈值常用于限制最大连接、最大Pending请求、最大并发请求和最大重试等资源。它与Resilience4j按失败率进入OPEN状态的“断路器状态机”不是完全同一个概念,面试时应说明语境。
13.2 Outlier Detection
异常实例检测根据连续5xx、成功率或本地连接错误等统计,暂时把Endpoint从该代理的可选集合中剔除,过一段时间再试探恢复。
边界:
- 它通常是每个代理的本地判断,不保证全网同时剔除。
- 样本少时容易误判。
- 下游整体故障时不能把所有实例无限剔除,需最大剔除比例。
- 业务4xx通常不应当作实例故障。
- 慢请求、连接失败和5xx的权重应按业务校准。
13.3 熔断不是降级结果
代理可以快速拒绝,却不知道该返回“库存未知”“稍后重试”还是“进入待确认”。业务服务仍需把基础设施错误映射为稳定领域状态。
十四、灰度、金丝雀与镜像流量
按权重把90%流量给v1、10%给v2,只说明代理路由概率,不保证每个小时间窗精确90/10。连接复用、样本数和哈希都会造成波动。
生产灰度步骤:
- 先验证v2配置和证书已下发,目标代理无NACK。
- 用Header或内部账号做定向验证。
- 从极小权重开始,按版本观察业务成功率、P99、资源和下游影响。
- 确认数据库Schema、缓存Key和消息事件兼容。
- 逐步放量,每一步等待足够观察窗口。
- 回滚时同时考虑旧连接和配置传播,不把“权重改为0”当瞬时切断。
流量镜像会复制请求但通常丢弃镜像响应。若镜像请求能写数据库、发短信或扣库存,就会产生真实副作用。镜像目标必须只读、使用隔离数据或显式禁用副作用。
十五、代理遥测能看到什么
建议至少观察:
- 请求数、成功率、响应码和P50/P95/P99。
- 上游连接建立、活动连接、连接失败和重置。
- Pending请求、并发请求和熔断拒绝。
- 重试Attempt、重试成功率和重试溢出。
- 每Cluster、Endpoint、Zone和版本流量。
- xDS连接、配置版本、ACK/NACK和同步状态。
- mTLS握手失败、证书剩余时间和SDS更新。
- Sidecar CPU、内存、文件描述符和事件循环延迟。
代理只知道网络视角。HTTP 200可能包含业务错误码,异步消息可能在响应后失败,数据库提交可能发生在客户端超时前。必须把traceId、业务流水号和应用指标关联起来。
十六、Sidecar与Ambient形态
| 维度 | Sidecar | Ambient或节点共享形态 |
|---|---|---|
| 部署 | 每个工作负载Pod一个代理 | 节点级安全隧道加可选L7代理等 |
| 资源成本 | 随Pod数增长 | 可减少每Pod代理成本 |
| 故障域 | 单Pod代理故障影响该Pod | 共享组件故障域可能更大 |
| 升级 | 需滚动工作负载或特定热升级机制 | 基础设施组件可独立升级 |
| L7能力 | 通常靠近应用完整处理 | 可能按需经过L7Waypoint等组件 |
Ambient是产品演进方向之一,具体能力、限制和成熟度依版本而变。不能把Sidecar配置原样复制后就假设Ambient行为完全一致。迁移前要验证流量捕获、身份、L7策略、可观测性和故障域。
十七、Mesh、Spring Cloud、Gateway怎么分工
| 组件 | 最适合的职责 | 不应单独承担 |
|---|---|---|
| Spring Cloud客户端 | Java内调用、LoadBalancer、Feign、业务降级适配 | 多语言统一mTLS |
| Service Mesh | 服务间mTLS、代理路由、通用遥测和网络治理 | 领域幂等和事务 |
| API Gateway | 南北向认证、API聚合、外部协议和配额 | 所有东西向细粒度代理 |
| Kubernetes Service | 稳定寻址和平台四层转发 | 七层业务路由和工作负载证书 |
| Nacos/Consul | 注册、健康、配置或服务网络控制面 | 业务数据一致性 |
双栈治理最常见的问题是重复配置:Feign重试一次、Spring Cloud LoadBalancer重试一次、Sidecar再重试两次;应用超时3秒、代理超时15秒;SDK熔断认为实例不可用而代理仍继续发送。迁移时要建立能力所有权矩阵,逐项决定保留在哪一层。
十八、Java 8/Boot 2与Java 17+/Boot 3边界
Mesh代理运行在独立进程或基础设施层,一般不依赖业务JDK版本。两条Java基线的差异主要在应用接入:
| 项目 | JDK 8 / Boot 2.7 | Java 17+ / Boot 3.x |
|---|---|---|
| 命名空间 | Java EE依赖常见javax.* | Jakarta依赖迁移到jakarta.* |
| 观测 | Sleuth等旧链路体系常见 | Micrometer Observation/Tracing主线 |
| 健康 | Actuator探针可用,按2.x配置验证 | Actuator与Kubernetes探针按3.x配置验证 |
| HTTP客户端 | 旧Feign/RestTemplate生态较多 | 新版Feign、RestClient/WebClient等组合 |
| Spring Cloud | 选择与Boot 2.7兼容发行列 | 选择与具体Boot 3.x兼容发行列 |
共同要求:传播trace上下文和业务Deadline、使用幂等键、实现SIGTERM优雅关闭、不要与Mesh重复重试、暴露业务指标。完整Boot差异见Java 17+与Spring Boot 3.x。
十九、JDK 8 Demo:证明多层重试会乘法放大
public class RetryMultiplicationDemo {
static int attempts;
interface Call {
boolean execute();
}
static boolean retry(int maxAttempts, Call call) {
for (int i = 1; i <= maxAttempts; i++) {
if (call.execute()) {
return true;
}
}
return false;
}
public static void main(String[] args) {
boolean result = retry(2, new Call() { // 网关层
public boolean execute() {
return retry(2, new Call() { // Sidecar层
public boolean execute() {
return retry(3, new Call() { // HTTP客户端层
public boolean execute() {
attempts++;
System.out.println("downstream attempt=" + attempts);
return false;
}
});
}
});
}
});
System.out.println("result=" + result + ", attempts=" + attempts);
}
}输出会到12次下游尝试。它兼容JDK 8;Java 17+可用Lambda简化语法,但不会改变2 × 2 × 3的容量事实。生产应把重试集中在最了解错误语义的一层,其他层关闭或共享总预算。
二十、商业场景:支付调用库存与风控
订单服务调用库存和风控时:
- 用户请求进入Gateway,完成用户认证和外部配额。
- 订单Sidecar根据Route选库存Cluster和Endpoint。
- 双方使用工作负载mTLS,库存入站策略只允许订单身份。
- 请求携带
orderNo幂等键和端到端Deadline。 - 库存本地事务用唯一流水和条件更新扣减。
- 若响应丢失,代理不应无限重试;订单按
orderNo查询库存事实。 - 新库存版本先按Header定向,再按1%、5%、20%逐步放量。
- 代理指标发现网络错误,业务指标确认扣减成功率,二者共同判断发布。
Mesh保证链路身份和通用流量治理,库存唯一约束保证重复请求不重复扣减,订单状态机处理结果未知。三个层次不能互相替代。
二十一、关键失败窗口
| 窗口 | 现象 | 恢复方向 |
|---|---|---|
| 控制面已保存但代理未收到 | 新路由只在部分实例生效 | 查xDS连接与版本分布 |
| 代理收到但NACK | 保留旧配置 | 查错误详情和资源依赖 |
| EDS已更新但旧连接存在 | 已摘除Pod仍有请求 | 区分新旧连接并Drain |
| SDS轮换失败但旧证书未到期 | 短期正常,之后集中握手失败 | 监控剩余有效期并修复SDS |
| 上游超时但下游已提交 | 客户端认为失败,业务实际成功 | 幂等键和事实查询 |
| 灰度权重回滚但连接复用 | v2仍短暂有流量 | 观察连接并有界排空 |
| Sidecar过载 | 应用正常但代理延迟、拒绝 | 查代理CPU、内存、FD和队列 |
二十一点五、Envoy Response Flag:从状态码反推失败层
Service Mesh 排查里只看 HTTP 503 很容易走错方向。同样是 503,可能是没有路由、没有健康上游、连接失败、资源溢出、上游超时或重试耗尽。Envoy 访问日志里的 RESPONSE_FLAGS 和 RESPONSE_CODE_DETAILS 能帮助你先定位失败阶段。
常见标志可按调用链理解:
flowchart TD
A["请求进入代理"] --> B{"Route是否匹配"}
B -- "否" --> C["NR<br/>No Route"]
B -- "是" --> D{"Cluster是否存在且有Endpoint"}
D -- "无健康上游" --> E["UH<br/>No Healthy Upstream"]
D -- "有候选" --> F{"连接是否建立"}
F -- "失败" --> G["UF<br/>Upstream Failure"]
F -- "成功" --> H{"资源阈值是否溢出"}
H -- "溢出" --> I["UO<br/>Overflow"]
H -- "未溢出" --> J{"上游是否按时返回"}
J -- "超时" --> K["UT<br/>Upstream Timeout"]
J -- "重试耗尽" --> L["URX<br/>Retry Exhausted"]| Flag | 常见含义 | 首要排查层 | 常见证据 |
|---|---|---|---|
NR | 没有匹配路由或路由配置不可用 | Listener、HCM、VirtualHost、Route、RDS | Host/Authority、Path、端口、协议识别、RDS同步状态 |
UH | 没有健康上游 | Cluster、EDS、Endpoint、Subset、健康检查 | Cluster名、Endpoint数量、Pod Ready、Outlier、Panic、Locality |
UF | 上游连接失败 | 网络、端口、TLS、服务方Sidecar | 连接拒绝、Reset、NetworkPolicy、mTLS握手、目标端口 |
UO | 上游资源溢出 | Cluster Circuit Breaker、连接池、Pending、重试 | max connections、pending requests、active requests、retry overflow |
UT | 上游请求超时 | Route Timeout、Per-try Timeout、下游执行 | 下游P99、线程池、DB锁、连接池等待、Attempt耗时 |
URX | 重试次数耗尽或重试相关失败 | Retry Policy、Retry Budget、Deadline | Attempt次数、重试条件、剩余预算、Retry Overflow |
UC | 上游连接中途断开 | 上游进程、连接池、HTTP/2、网络 | GOAWAY、Pod重启、连接年龄、节点网络 |
DC | 下游连接断开 | 客户端、网关、调用方取消 | 客户端超时、浏览器断开、Gateway取消、下游仍可能执行 |
排查顺序必须先定位“哪个代理打出的 Flag”。例如:
| 代理位置 | 意义 |
|---|---|
Gateway Envoy 返回 NR | 入口路由没有匹配,业务服务可能完全没收到请求 |
调用方 Sidecar 返回 UH | 调用方看到的目标 Cluster 没有健康 Endpoint |
调用方 Sidecar 返回 UF | 选到了 Endpoint,但连接或TLS失败 |
| 服务方 Sidecar 返回 403/401 | 请求已经到达服务方代理,可能是身份或授权策略拒绝 |
| 应用容器返回 500 | Mesh已经把请求转给业务,重点看业务日志、数据库和异常 |
不要把 Flag 当成绝对根因。它是代理视角的失败分类,还要结合 config_dump、clusters、certs、访问日志、Trace 和业务事实确认。特别是 UT、DC、UF 这类网络失败不能证明写请求没有执行;订单、库存、支付仍要按幂等键查询事实。
二十二、生产Runbook
22.1 503 NR:No Route
- 确认503由哪个代理产生。
- 查看请求Host、SNI、Path和端口是否匹配Listener与VirtualHost。
- 查看代理实际RDS配置,不只看控制面声明。
- 检查路由资源是否已下发、是否NACK、版本是否陈旧。
- 检查命名空间导出、服务可见性和协议识别。
22.2 503 UH:No Healthy Upstream
- 查看目标Cluster是否存在。
- 查看EDS端点数量、健康、优先级和Locality。
- 对照Kubernetes EndpointSlice和Pod Ready。
- 检查异常实例检测是否剔除过多端点。
- 检查Subset或版本标签是否把候选筛成空集。
22.3 503 UF或连接失败
- 区分DNS、连接拒绝、超时、Reset和TLS握手失败。
- 直接检查服务方Sidecar监听与业务容器端口。
- 检查NetworkPolicy、节点网络、MTU和Conntrack。
- 检查连接池、最大连接和Pending熔断阈值。
- 按Node、Zone和Endpoint拆分,定位局部网络故障。
22.4 mTLS握手失败
- 查看双方实际证书链、SAN身份、信任根和剩余有效期。
- 检查系统时间和证书轮换。
- 检查STRICT/PERMISSIVE和客户端TLS模式是否匹配。
- 检查信任域、跨集群信任和根证书迁移窗口。
- 查看SDS同步和Secret NACK,不输出私钥到日志。
22.5 xDS NACK
- 定位代理、资源类型、nonce、version和错误详情。
- 确认是LDS、RDS、CDS、EDS还是SDS。
- 检查引用资源是否存在、字段是否被当前代理版本支持。
- 保留Last Known Good,不要强制清空代理配置。
- 回滚或修正后观察全体代理ACK分布。
22.6 配置已改但流量没变
- 区分控制面对象、目标代理配置和真实流量三个事实层。
- 查看配置是否选中了正确工作负载和命名空间。
- 查看目标代理是否连接控制面、是否ACK最新版本。
- 查看Route是否被更高优先级规则覆盖。
- 区分旧连接与新连接,检查连接池和HTTP/2。
- 用按版本请求数证明真实分流,不只看配置页面。
22.7 Sidecar CPU或内存过高
- 按Listener、Cluster、连接、请求和统计基数拆分。
- 检查大量短连接、TLS握手、重试风暴和高基数指标。
- 检查配置规模、Endpoint数量和无效服务可见范围。
- 查看访问日志量、采样、Tracing和Filter成本。
- 调整资源前先消除重试和连接异常,否则只会推迟崩溃。
二十三、常见误区
| 误区 | 为什么错 |
|---|---|
| 上了Mesh就不需要SDK设计 | 业务幂等、状态机和领域错误仍在应用层 |
| mTLS等于用户授权 | 它主要证明工作负载身份,不证明用户能退款 |
| ACK表示全网生效 | 只表示某代理接受某响应,旧连接和其他代理可能未切换 |
| 控制面不在请求路径所以不重要 | 长期故障会阻断端点、路由和证书更新 |
| 重试越多越可靠 | 多层重试会乘法放大并攻击故障下游 |
| 权重10%必然精确10% | 小样本、连接复用和哈希都会波动 |
| Outlier Detection等于全局摘除 | 通常是各代理本地判断 |
| 流量镜像没有风险 | 写请求镜像可能产生真实副作用 |
| Sidecar和Ambient配置完全一样 | 捕获方式、L7路径和故障域不同 |
二十四、面试回答主线
先说Mesh将通用通信能力下沉到代理;再区分控制面计算配置、数据面转发真实请求;用Listener → Route → Cluster → Endpoint说明Envoy调用链;用LDS/RDS/CDS/EDS/SDS说明xDS;补充ACK/NACK与Last Known Good;再讲工作负载mTLS、重试乘法、连接级负载、灰度传播和Runbook;最后明确业务幂等、事务和授权仍由应用负责。
标准回答与追问见Service Mesh面试题。
更深的运行时调用链、配置收敛、连接与失败窗口见 Service Mesh 内部原理与生产治理。
二十五、关联知识点
- Kubernetes服务发现与传播窗口
- Service Mesh内部原理与生产治理
- Consul Connect
- Dubbo服务治理
- Spring Cloud完整调用链
- 分布式幂等
- 限流、熔断与降级
- Java 17+与Spring Boot 3.x
本章小结
Service Mesh的核心不是Sidecar这个形态,而是“控制面持续计算配置,数据面代理按本地已接受快照治理真实流量”。要真正理解它,必须同时掌握Envoy对象、xDS收敛、mTLS身份、连接和请求边界、重试与Deadline、配置传播窗口以及业务正确性边界。只有能从控制面对象一直追到代理实际配置、连接、Endpoint和业务结果,才算具备生产排查能力。
