服务网格 18:出口流量经过哪里,怎样约束访问
写了出口规则,应用就不能直连外部了吗 orders 在取得 inventory-v1 的报价后还会访问 external-stub。如果为这个目标声明 ServiceEntry 并配置出口网关,受代理接管的请求可以走 orders → sidecar → egress gateway → external-stub;但若同一个工作负载还能在网络层直接连上 stub,路由声明没有证明所有出口都经网关。这里必须同时问两个问题:代理把已捕获的请求送去了哪里?不经过代理的连接能否建立? 上图的实线是预期的代理路径,虚线是必须试探的绕过路径。ServiceEntry 让代理识别外部服务,VirtualService 等路由配置决定符合条件的请求经过出口网关;DestinationRule 中的 TLS 设置涉及指定连接段。它们都不能单凭对象存在证明应用无法通过其他地址、端口或未捕获流量出网。Istio 的 ALLOW_ANY 与 REGISTRY_ONLY 是代理对未知服务的处理模式,不是宿主机或集群范围的出站防火墙。 哪条连接加密,谁负责解析名字 以一个受控的 HTTP 测试站点为例,...
服务网格 17:入口网关怎样接到内部调用
HTTPS 入口返回 200,内部链路也经过 TLS 吗 读者访问 frontend,frontend 再请求 orders → inventory-v1 + external-stub。入口网关若终止浏览器的传输层安全协议(TLS),获得的是客户端到网关这一段的加密连接;网关转发到 frontend、工作负载间的连接要分别确认。入口 HTTP 200 至多说明本次完整请求得到了响应,不说明内部使用了双向 TLS(mTLS),更不证明有人无法绕开入口直接访问后端。 上图把客户端、入口网关、frontend 和内部上游画成四个观察点。TLS 握手里使用的服务器名称指示(SNI)与随后 HTTP Host/:authority 是不同字段:客户端可以在证书匹配的域名上发送另一个 Host。TLS 失败时请求尚未进入应用层路由;证书通过但 Host 或 path 不匹配,是网关路由层的另一类负例;命中路由以后内部服务返回 502/503,还需查看哪一跳报错。不能把这三类失败都记作“网关拒绝”。 匹配、来源地址、身份分别在哪里生效 在网关上声明监听器和 TLS 证书,再把匹配的 Hos...
服务网格 16:故障注入与流量镜像怎样避免误判
影子请求失败,为什么主请求仍成功 把 orders → inventory-v1 的只读报价复制一份给 inventory-v2,主链路可能照常返回 v1 的结果,影子服务也记录一条请求。这并不矛盾:流量镜像(mirroring/shadowing)复制请求,但主请求不等待影子目标返回。若被复制的是 POST /reserve,影子库存即使不参与主响应,也可能单独写入副作用账本;“不影响主响应”绝不等于“不会执行写入”。 隔离写入不是只给 v2 改个名字。两个实例都执行同一业务副作用时,必须使用不会触达真实库存、账务和通知的独立账本;测试输入也要与生产数据隔离。镜像尽力而为,影子响应和耗时不能替代主请求的成功判据,影子收到的请求数也不能不经对照就当作主请求数。 故障发生在哪一侧,决定了能观察到什么 Istio VirtualService 可在客户端侧为 HTTP 流量指定延迟或 abort(注入错误响应),也可以定义镜像目标和比例。延迟、直接 abort 与应用提交后丢失响应有不同的执行路径:代理若在发往上游前直接返回错误,上游账本可能没有记录;应用已写账本再延迟,则客户端失...
服务网格 15:连接限制与异常实例摘除有什么区别
库存实例变慢,该拒绝请求还是换一台 同一批 orders → inventory 调用中,inventory-v1 响应变慢,而 inventory-v2 仍能处理请求。“连接数满了”与“v1 连续失败”需要两种不同的判断:前者保护某个代理指向上游集群的连接、排队请求或活跃请求等资源;后者依据目标实例的错误信号,暂时从该代理的健康负载均衡集合中摘除异常端点。把两者笼统叫作“熔断”,会让排障时把局部资源耗尽误判为实例不健康。 Envoy 的 circuit breaking 是分布式但不集中协调的代理限制:最大连接数、待处理请求、活跃请求、重试等分别计数,边界由各代理所见的 cluster、优先级及配置决定。达到待处理请求上限可能让新请求溢出,但不会据此断言整个服务的全局每秒请求数受到了精确限制。尤其是 HTTP/2 复用下,多请求不必对应多连接;连接阈值也不等于并发请求上限。实际连接数在实现与连接池边界下不宜写成严格永不越过设定值,需核对所用版本文档和代理计数器。 异常实例检测(outlier detection)是被动健康检查:根据代理观测到的连续错误、时间窗口成功率等信号,...
服务网格 14:重试为何会放大副作用
没收到响应,是否可以再发一次 不行,除非请求本身可安全重复,或者应用明确实现并验证了去重。第 13 篇已经看到客户端退出后上游仍可能完成;本篇在同一 inventory 的合成 POST /reserve 上检查响应丢失之后重发。业务输入固定为 operation_id=op-01、X-Request-ID=sm-01-repeat,两次使用相同标识不是应用幂等的证明。 库存 handler 的顺序是解析操作 ID → 追加内存账本并记录 201 → 人为延迟 400ms → 写响应。客户端第一次等待只有 100ms;看到超时,不知道服务器停在提交前还是提交后。第二次把等待放宽到 2s 并发送同一输入,若没有去重便得到第二笔。对 read 请求的重试也可能增加下游负载,但不会由此自动推出“读请求永远安全”:日志、计费、外部副作用或应用错误实现都要另查。 两层重试如何相乘 假设仅作为配置上界的示意:SDK 对失败调用最多尝试 2 次,每一次调用都被代理各尝试 2 次;一笔用户操作最多触发 2 × 2 = 4 次后端尝试,而不是“额外重试两次”。这不是本仓库实际代理配置或观测比例。...
服务网格 25:503、连接重置与尾延迟如何定位
先问“哪一跳”,再问“是什么错误” 一个用户请求进入 frontend → orders 调用链(orders 先调用 inventory,成功后再调用 external-stub)。客户端的 503、连接重置或一次很慢的成功响应,分别只是客户端这一观察点的事实。DNS 解析、EndpointSlice、代理路由、上游连接、mTLS、授权、应用处理、回包和遥测管道都可能改变症状;控制台上的一张 503 截图无法确定故障发生在哪层。 先记录一个有唯一请求 ID 的正常样本,包括当前应用版本、带实际 endpoint 的 Service、所选代理的 route/cluster、双方代理访问日志、应用日志、客户端出口码与延迟。故障时先找第一个和正常样本不同的观察点:DNS 不通时不必先改 JWT;已有 endpoint 也不证明端口在监听;mTLS 握手失败不等同于授权 DENY;AuthorizationPolicy 被拒绝时也不该优先调整重试次数。每换一个诊断假设,都要说明它能解释哪条证据、还有哪条证据不能解释。 分层 需要的证据 不能代替的事实 服务发现 DNS ...
服务网格 24:自动追踪为什么仍会断链
有代理 Span,不代表有一条完整的 trace Envoy 可以为经过它的请求产生 Span,但一次 frontend → orders 调用链(orders 先调用 inventory,成功后再调用 external-stub) 会跨多个应用和代理。上游代理发出的 Span 想与下游代理的 Span 连成同一条 trace,应用必须把收到的追踪上下文带到新发起的请求;代理无法替应用跨越一个由应用新建的 HTTP 请求边界。X-Request-ID 方便人工关联日志,但不是 W3C traceparent 的替代品,两个值都出现也不保证父子关系正确。 累计工程的 examples/service-mesh/apps/mesh-demo/main.go 现已在下游 fetch 中转发有限的 W3C 与 B3 上下文头,并保留 X-Request-ID;应用仍没有自行创建 Span。复制 traceparent 可保留上游上下文,但不会自动测出业务方法耗时,也不能证明代理采用了相同传播格式。测试需选定一种格式,核对实际 Span 的 trace ID 和 parent ID,不要把...
服务网格 23:网格指标怎样用于 SLO
先选服务边界,再算错误率 frontend → orders 调用链(orders 先调用 inventory,成功后再调用 external-stub)跨越多跳。Istio 的 HTTP 请求指标可以分别由客户端代理和服务端代理报告,reporter="source" 与 reporter="destination" 并不是两个互不重叠的用户请求集合。若把两侧 istio_requests_total 直接相加,或者把库存服务的请求数当成 frontend 对用户的请求数,分母从一开始就错了。 要回答“frontend 对用户的成功率”还是“inventory 入站调用的成功率”,先选择一个明确的边界,再固定 destination_workload、命名空间、reporter、窗口和所包含的 HTTP 状态。示例固定在 service-mesh-lab 命名空间;若采集端汇聚多个集群,还须按实际暴露的集群标签限定同一目标集群,并在三个选择器中保持一致。以下 PromQL 仅是待在冻结版本核对标签与指标类型后的查询示意,不是本站抓取到的值...
服务网格 22:访问日志怎样区分代理失败和业务失败
同一个 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 先调用 inv...
服务网格 21:认证成功为何仍会被拒绝
证明“是谁”不等于证明“能做什么” orders 以正确工作负载证书连接库存,只说明对端代理能够验证它的工作负载身份;一名最终用户带有效 JWT,也只说明令牌在指定签发者、密钥、受众及有效期等规则下通过校验。业务是否放行,还要看作用于 inventory 的授权策略与请求属性。对等身份来自 mTLS,最终用户身份来自请求令牌;两者不能互相替代,更不能把客户端自填的 X-Request-ID 当作认证结果。 Istio 的 RequestAuthentication 有一个很容易写错的边界:携带了不合法的令牌会被拒绝;没有携带令牌的请求默认仍能进入后续处理。如果业务要求“必须提供有效 JWT”,还需增加匹配 requestPrincipals 的 AuthorizationPolicy。在 HTTP 路由中,拒绝可能发生于请求认证、授权、TLS 握手,甚至应用自身;只有确认策略作用域、代理记录和应用是否收到该请求,才能说清拒绝位置。 把两种身份与两阶段策略拆开测试 仍使用 orders → inventory-v1。先为两个工作负载配置不同 ServiceAccount,确认目标...

