影子请求失败,为什么主请求仍成功

把 orders → inventory-v1 的只读报价复制一份给 inventory-v2,主链路可能照常返回 v1 的结果,影子服务也记录一条请求。这并不矛盾:流量镜像(mirroring/shadowing)复制请求,但主请求不等待影子目标返回。若被复制的是 POST /reserve,影子库存即使不参与主响应,也可能单独写入副作用账本;“不影响主响应”绝不等于“不会执行写入”。

主链路、镜像影子链路与故障注入位置

隔离写入不是只给 v2 改个名字。两个实例都执行同一业务副作用时,必须使用不会触达真实库存、账务和通知的独立账本;测试输入也要与生产数据隔离。镜像尽力而为,影子响应和耗时不能替代主请求的成功判据,影子收到的请求数也不能不经对照就当作主请求数。

故障发生在哪一侧,决定了能观察到什么

Istio VirtualService 可在客户端侧为 HTTP 流量指定延迟或 abort(注入错误响应),也可以定义镜像目标和比例。延迟、直接 abort 与应用提交后丢失响应有不同的执行路径:代理若在发往上游前直接返回错误,上游账本可能没有记录;应用已写账本再延迟,则客户端失败也可能对应真实写入。不能用一个代理注入的 503 来模拟“操作已经提交但响应丢失”;应由应用控制提交后的延迟/断开,随后核对账本。

还要注意组合边界:Istio VirtualService 字段说明,客户端侧启用 fault 时,该侧超时或重试不会启用。不能一边在同侧加故障注入,一边将“未发生重试”归因于业务策略。对重试放大的验证应优先保留应用注入故障,另以不组合 fault 的代理配置测试重试;每组记录发往上游的尝试数,而不是只看客户端最终状态码。第 14 篇的合成账本正是应用提交后延迟响应的另一类故障。

正常与失败路径:先跑进程基线,再补代理

在 examples/service-mesh/ 可从只读调用和合成写入基线开始:

1
2
bash scripts/run-00.sh
bash scripts/run-01.sh

run-00.sh 的成功报价是主链路基线,但工程中 inventory-v2 的存在不表示已有镜像;run-01.sh 在库存提交后延迟响应、人工重发同一操作 ID,能检验“客户端失败不等于没有副作用”,但这仍不是代理注入或影子请求。要做本机模拟,可在两个隔离的库存进程上用同一合成输入分别执行 POST /reserve,再分别查 GET /ledger;它只模拟两个业务副本会各自写账,不能据此声称观察到 Envoy 的异步镜像。错误路径还应分别检验“影子写入被隔离”与“错误地指向主账本导致重复写入”;只在完全隔离的测试账本里演示后者。

真正的代理实验须在隔离环境记录已生效的路由/镜像/fault 配置、代理出站请求、v1/v2 各自账本和主客户端退出码;分别测试正常镜像、影子不可用、注入 abort、应用提交后丢失响应。主链路的判据看主响应,影子副作用看隔离账本,故障位置由代理与应用同一请求 ID 的日志对齐。当前故障注入、真正的镜像和影子不可用对照均为 NOT_RUN;下表不填写假设结果。

待验收场景 主客户端结果 主账本 影子隔离账本 代理注入/镜像证据
正常镜像 待运行 待运行 待运行 待运行
影子不可用 待运行 待运行 待运行 待运行
注入 abort 待运行 待运行 待运行 待运行
应用提交后响应丢失 待运行 待运行 待运行 待运行

练习与参考解答

  1. 请求经代理收到注入的 503,库存没有该请求 ID,能证明“服务端执行后丢失响应”吗?参考解答:不能。先核对代理注入点;如果请求根本没有转发到库存,就无法推出应用提交。要验证结果未知,应在应用写入后制造响应延迟,再检查客户端与账本。
  2. 主请求 200、影子服务返回 500,如何修改实验让影子操作可安全观察?参考解答:影子独立部署并隔离账本、外部写入与通知,给两条路径带可关联的请求 ID,各自读取服务端结果;不把影子 500 当主请求 500,也不把 200 当影子没有副作用的证明。

官方参考与系列导航

  • Istio VirtualService 参考:fault、mirror 及客户端侧 fault 与 timeout/retry 的组合限制。
  • Istio 流量镜像:影子请求在关键响应路径之外;示例模板是否可直接复制须以固定版本与实际渲染核验。

系列导航:15 限制与摘除 → 16 故障与镜像(本文)→ 17 入口网关。