同一个 503,可能出现在不同的层

客户端看见 503,并不能判断是 inventory 自己返回、代理连接不上库存实例,还是请求根本没有选到可用目标。第 03 篇讨论了 listener、route、cluster 和 endpoint;第 21 篇又加入认证、授权两个可能提前结束请求的位置。访问日志的任务,是把代理观察到的结束原因与应用实际做过的事情对齐,而不是只重复一列 HTTP 状态码。

Envoy 的响应标志、%RESPONSE_CODE_DETAILS%、%UPSTREAM_HOST% 和 %UPSTREAM_TRANSPORT_FAILURE_REASON% 能给出比状态码更细的线索,字段可用性及具体文字随代理版本、过滤器和配置而变。没有匹配 route、上游连接失败、上游主动断开,都需要分别查看代理实际记录;有 UPSTREAM_HOST 也不保证应用处理完请求。客户端侧代理、服务端侧代理、网关和应用还可能各自记录同一个逻辑请求,必须写清观察点。

同一请求标识贯穿客户端、出入站代理和应用日志,用处理位置区分失败类别

用请求 ID 对齐三条路径

实验输入固定为 frontend → orders 调用链(orders 先调用 inventory,成功后再调用 external-stub) 的同一只读 SKU,每个场景生成独立 X-Request-ID。在隔离环境启用可检索的 Envoy 访问日志,将请求 ID、响应码、响应标志、详情、上游地址和代理身份一起记录;当前 Go 应用已有 request_id、role、status 日志,可据此判断哪些应用 handler 实际运行。保存代理最终生效的日志配置;“启用了 Telemetry 资源”并不等于采集端收到日志。

第一组正例走正常 quote:从客户端收到的响应回溯 frontend、orders、inventory 和 external-stub 的日志。第二组移除测试路径的 route,仅在明确被改动的代理核对无路由详情和下游响应;不要预设必定是 503,route 匹配失败与目标 cluster 无健康端点也不能合成同一种问题。第三组保持 route 和 endpoint 可见,但让测试 Service 指向没有监听者的上游端口,对照代理连接错误及库存应用是否收到请求。第四组让应用自身返回 503:可以使用现有 frontend 的“候选上游配置为空”分支,但它是应用级空地址配置,不是 Kubernetes 空 EndpointSlice。

场景 首要取证问题 实际标志、详情、应用记录
正常 quote 哪些代理和应用见到同一请求 ID? NOT_RUN:无 Kubernetes/Istio/Envoy
无路由 哪个代理提前结束,是否确无上游处理? NOT_RUN
错误上游端口 当前 route/endpoint 是什么,失败在连接哪一段? NOT_RUN
应用返回 503 目标应用是否记录同一 ID 和主动返回的 503? NOT_RUN

这些并非“状态码到根因”的静态对照表。如果应用确实返回 503,上游响应标志和详情可能与代理本地生成的 503 不同;如果代理有重试,单个客户端请求又可能对应多个上游尝试。记录每次尝试及最终响应,不用应用的最后一行日志替代客户端结果,更不要把没有应用日志直接当作应用没有执行的充分证明:还要排查采集丢失。

给每个错误保留代理结束原因

以下命令在 examples/service-mesh 目录执行,使用 04 章 Kubernetes 1.33.4 / Istio 1.27.0 sidecar 基线,应用容器名 app。先清理前章授权、故障与出口策略;下列预期值尚不是集群实测结果。

1
2
3
4
5
export SM_CONTEXT=kind-service-mesh-sidecar
k() { kubectl --context="$SM_CONTEXT" -n service-mesh-lab "$@"; }
k apply -f mainline/13/probe.yaml
k rollout status deploy/sm-probe --timeout=120s
OUT="evidence/mainline-22/$(date -u +%Y%m%dT%H%M%SZ)"; mkdir -p "$OUT"

mainline/22/logs.yaml 使用默认 envoy 日志 provider;Istio 1.27.0 的默认访问日志含 request ID、response flags、response code details 和 upstream host。如果安装时改过日志格式,应先保存 MeshConfig 并确认字段存在,不能按列位置猜测含义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
k apply -f mainline/22/logs.yaml
k apply -f deploy/kubernetes/inventory-route.yaml
k exec deploy/sm-probe -c curl -- curl -fsS -H 'x-request-id: ch22-ok' 'http://inventory:8080/quote?sku=paper' > "$OUT/normal.json"
k apply -f mainline/22/no-route.yaml
k exec deploy/sm-probe -c curl -- curl -sS -w '\n%{http_code}\n' -H 'x-request-id: ch22-no-route' 'http://inventory:8080/quote?sku=paper' > "$OUT/no-route.txt"
k apply -f deploy/kubernetes/inventory-route.yaml
k get svc inventory -o yaml > "$OUT/service-before.yaml"
k patch svc inventory --type=json --patch-file mainline/25/bad-port.json
k exec deploy/sm-probe -c curl -- curl -sS --max-time 3 -w '\n%{http_code}\n' -H 'x-request-id: ch22-connect' 'http://inventory:8080/quote?sku=paper' > "$OUT/connect.txt"
k apply -f "$OUT/service-before.yaml"
k exec deploy/sm-probe -c curl -- curl -fsS -H 'x-request-id: ch22-recover' 'http://inventory:8080/quote?sku=paper' > "$OUT/recovered.json"
k logs deploy/sm-probe -c istio-proxy > "$OUT/source-proxy.log"
k logs deploy/inventory-v1 -c app > "$OUT/inventory.log"
istioctl --context="$SM_CONTEXT" proxy-config endpoints deploy/sm-probe -n service-mesh-lab -o json > "$OUT/endpoints.json"

无路由组预期出现 route_not_found 一类详情与 404;连接组保持路由但 upstream host 端口错误,预期连接失败详情。实际 flags 和错误文字以固定版本日志为准,不把本文写成不可变的状态码字典。配置传播有延迟,需在请求前确认对应代理已同步;若仍看到旧配置,不重复解释旧结果。

应用 503 对照复用 15 章 fault-lab:请求 /quote?mode=fail,保存 fault-a/fault-b 的应用日志以及 sm-probe 的上游响应记录。该组必须实际进入应用,而错误端口组不能由应用主动生成;缺日志时先验证采集完整性。完成后删除 logs.yaml,恢复原 inventory 路由和 Service,后续排障可按需保留日志配置但应注明。

固定源码入口:Istio 1.27.0 pilot/pkg/model/telemetry.go。该链接用于核对配置生成或执行机制;完整资源和命令保存在 examples/service-mesh/mainline/22/。静态检查通过不等于集群实验通过。

练习与参考解答

  1. 两条客户端日志都是 503,其中一条 inventory 有同一请求 ID 的 503 应用日志,另一条完全没有。可以确定第二条是无路由吗?参考解答:不能;还可能连接失败、日志未采集或请求被认证授权提前结束。先比对对应代理的 route、响应详情、上游地址及日志采集完整性。
  2. 看到 UPSTREAM_HOST,是否可以断言业务写入成功?参考解答:不能。它只帮助定位代理选择或尝试的上游;写入要核对应用处理记录和最终副作用账本。

官方资料与系列导航

系列导航:21 认证成功为何仍会被拒绝 → 22 访问日志怎样区分代理失败和业务失败(本文)→ 23 网格指标怎样用于 SLO。