服务网格 03:Envoy 怎样转发请求
从应用的上游地址移到代理监听端口
此前 orders 直连 inventory-v1。第 02 篇说明 Service 地址、端点和连接并不等价。若把 orders 的库存 URL 指向本地 Envoy listener,代理必须回答两个问题:收到一个 HTTP 请求时匹配哪条路由?挑选哪个实际后端建立上游连接?本篇先用独立 Envoy 进程解释这些步骤;它没有 Pod 注入,也没有 Istiod 或 xDS 下发。
图上方的监听地址接收下游连接,图右侧的两个 inventory 进程是候选上游。业务请求并非每次都到后端:没有匹配路由可以由代理直接返回错误,选中 cluster 但后端不可连接则失败在建立上游连接阶段。用同一个 HTTP 状态码反推故障层级会丢失信息。
将五层选择映射到一次请求
- Listener 接受指定地址与端口上的连接;这是“谁能够连上代理”,还没选业务后端。多个 listener 或传输套接字会改变入口形态。
- Filter chain 根据连接属性选择网络过滤器链;可以有 TLS 处理与匹配条件。本篇明文 HTTP 样例只有一条过滤器链,不推论 SNI、ALPN 或 mTLS 的默认行为。
- HTTP connection manager 与 route 解析 HTTP 请求,并按 virtual host、路径等条件匹配 route。
/quote路由到inventorycluster;/unavailable路由到显式配置的不可连接 cluster;/no-route不匹配任何路由。route 也可能返回直接响应或重定向,而非总是转发。 - Cluster 包含发现与连接策略,本例静态声明两个 inventory 实例,设
ROUND_ROBIN作为负载均衡策略。它并不保证任意两个 HTTP 请求均匀地落到两个版本;长连接、并发、健康和尝试数都影响样本观察。 - Endpoint 是选中的实际地址和端口;还要通过上游连接才能读取应用响应。
/unavailable虽能匹配路由并找到配置中的 endpoint,但指向未监听的 loopback:1,因而不能得到 inventory 响应。
用户在 orders 侧只看到发往 Envoy 的请求;要证明经代理转发,至少交叉检查代理访问日志里的 X-Request-ID、upstream_host、后端 inventory 日志中的同一标识,以及最终返回的 inventory_version。config_dump 只能确认进程内配置存在,不能单独证明请求经过配置;此处配置来自静态 YAML,没有“xDS 已 ACK”的阶段。第 06–07 篇才研究控制面下发及拒绝。
可执行配置与当前执行结果
实验继续使用 examples/service-mesh/apps/mesh-demo/main.go 的同一组服务。examples/service-mesh/deploy/envoy/static.yaml.tmpl 固定了 listener、HTTP connection manager、route、两个 cluster 和两个 inventory endpoint;scripts/run-03.sh 在本地绑定随机 loopback 端口,渲染该模板,先调用 envoy --mode validate,再启动两个版本、external-stub、orders 和 frontend。脚本记录代理 Admin API 的 config_dump、24 个带标识的请求、无匹配路由与不可连接上游的失败响应,以及两个合成账本。
若可从官方发布资产获取 Envoy v1.37.0 Linux x86_64,核对下载 SHA-256 0a5729ee4e980d346ebcee80f18e7efe5232b91141bb4c776ec3adcca786e60c 后,在 examples/service-mesh/ 执行:
1 | |
脚本会生成 evidence/03/<UTC 时间>-<PID>/,保存二进制与配置 SHA、启动命令、原始响应、代理及应用日志、退出码和判据;只会终止自己启动的进程。Admin 端口仅绑定 loopback。实验的成功判据是同一业务输入先后实际返回 v1、v2,且每条请求在 Envoy 访问日志与相应库存实例日志中均有记录;两个失败请求应在代理直接拒绝与上游连接失败两个位置终止,断言脚本在不匹配时返回非零。
当前实验为 NOT_RUN。 宿主没有现成 Envoy,官方资产 API 的二进制下载在 120 秒内仅接收约 1.8 MB 后超时,未获取完整 90 MB 的资产,既未校验完整 SHA,也未调用 --mode validate 或启动代理。上述配置是待实测的完整实验输入,不是已通过版本兼容验证的配置。失败日志、官方资产元数据和复跑命令见 writing-plans/service-mesh/research/03.md。因此不能在这里填写“v1/v2 分流比例”、访问日志中的 response_flags 或代理返回的具体 HTTP 状态。图解释机制,不伪装成运行拓扑的抓包结果。
反例、定位与边界
试想 /no-route 返回代理本地错误:修改库存实例的 Go 处理器不能修复 route 未匹配;应先看配置的 route 条件及 Envoy 访问日志。反过来,/unavailable 已匹配 cluster,即便能在 config_dump 看到 endpoint,连接目标端口无人监听仍然失败;应看 upstream_host、连接失败详情与后端是否有相同 request ID。这两种失败位置需要真实代理运行结果核对,静态配置只能展示意图。
若 orders 改成直连库存进程,应用响应可能与代理转发时一样,却不再经过 Envoy;单看业务字段不能证明经过代理。静态 Envoy 只能解释这个本机独立进程的路由过程,不自动推导 Kubernetes Service、sidecar 流量劫持或 ambient waypoint 的行为。
练习与参考解答
- 一个请求在 Envoy 日志里有
upstream_host,却在该库存实例日志里没有对应 request ID。能否宣布应用已处理?参考解答:不能。地址被选中不等于连接成功或应用读到完整请求;核对代理的响应标记/详情与上游连接失败事件,按相同标识搜索其他库存实例日志。若缺乏请求标识关联,应先补证据,不从 cluster 配置推导执行结果。 - 将
/quote路由的 cluster 名改为不存在的名字,或把两个 endpoint 都指向未监听端口,预期失败层级有何差异?参考解答:不存在的 cluster 引用可能在--mode validate或配置接受阶段被拒,必须以固定版本验证错误为准;不可连接端口的配置可能能通过校验,但运行时建立上游连接失败。一个是配置/依赖错误,一个是已接受配置下的实际连接错误,不能用“配置已下发”同时证明两者成功。
官方资料与系列导航
- Envoy v1.37.0 静态配置入门:配置对象与本机进程示例。
- Envoy v1.37.0 Listener 与 HTTP routing:filter chain、虚拟主机和 route 的关系。
- Envoy v1.37.0 Cluster manager 与 Endpoint API:上游候选集合与端点配置。以上链接定位到选定文档版本,运行结果仍需待实测。
系列导航:00 一次服务调用需要哪些基础条件 → 01 SDK、网关与服务网格分别处理什么 → 02 Service 地址怎样到达 Pod → 03 Envoy 怎样转发请求(本文)→ 04 Sidecar 怎样接管流量。
