跳到内容

第 6 卷 / 第 14 章 / 第 1 课

14.1 服务发现、网关、BFF 与配置边界 ​

服务拆开以后,调用方首先面对的不是“怎么发 HTTP”,而是实例地址会变化、实例可能尚未就绪、入口需要统一治理、不同客户端需要不同数据形状。

本课先建立调用拓扑。超时、重试、断路器和过载保护留到下一课。

服务发现回答两个问题 ​

服务发现需要回答:

  1. 哪些实例属于目标服务?
  2. 哪些实例此刻可以接收请求?

常见方式有两类:

  • 客户端发现:调用方从注册表取得实例并负载均衡;
  • 服务端发现:调用方访问稳定地址,由负载均衡器或平台代理选择实例。

以带选择器的普通 Kubernetes ClusterIP Service 为例:DNS 返回 Service 的虚拟 IP,平台根据 EndpointSlice 中的端点状态把流量转发给就绪 Pod。下面假设 Service 名为 scoring,位于 default 命名空间,集群域为 cluster.local。应用代码不应缓存 Pod IP 当成永久地址。

text
caller
    ↓ DNS
scoring.default.svc.cluster.local
    ↓ Service / EndpointSlice
ready scoring Pods

无头 Service 的 DNS 可以直接返回端点地址,不能照搬虚拟 IP 这条路径。publishNotReadyAddresses: true 还会让 EndpointSlice 的 ready 条件视为真;“经 Service 访问”并不无条件等于“只访问就绪实例”。就绪状态传播也有延迟,已建立的连接和在途请求仍需排空。Service 与 EndpointSlice 条件说明了这些差异。

存活探针持续失败会触发容器重启,就绪探针失败则让实例退出常规流量路由,本身不触发重启。配置启动探针后,存活和就绪探针会等它成功才开始检查。把依赖数据库短暂失败直接当作存活失败,可能导致所有实例同时重启并放大故障。

API Gateway 是边界,不是业务中心 ​

网关适合处理跨入口的一致性职责:

  • TLS 终止、身份验证和基础授权;
  • 路由、协议转换和版本迁移;
  • 请求大小限制、速率限制和入口观测;
  • 少量稳定的响应聚合。

网关不应拥有核心业务流程。若“结算比赛、更新积分、发送奖励”的规则写在网关里,内部调用、批处理和消息入口会绕过它,网关也会成为高耦合发布瓶颈。

网关还必须传播客户端身份、追踪上下文和取消信号。身份头不能照单转发:应移除客户端伪造的内部身份头,传递下游可以验证的身份凭据;下游仍需检查用户能否操作指定对象。经过网关,不等于拿到所有比赛的管理员通行证。

BFF 为客户端体验负责 ​

Web、移动端和第三方 API 往往有不同需求:

  • 移动端更在意请求次数和弱网;
  • Web 端可能需要更细粒度、可并行的数据;
  • 第三方 API 需要长期兼容和严格配额。

BFF(Backend for Frontend)可以为一种客户端组合稳定的展示模型:

text
Mobile App → Mobile BFF ─┬→ Player Service
                         ├→ Ranking Service
                         └→ Reward Service

BFF 可以裁剪和聚合数据,但不应成为另一个共享企业总线。每增加一次扇出,都要计算最慢依赖、部分失败和总延迟预算。

假设同一统计窗口中,三个必需依赖的成功率均为 99.9%,失败相互独立,且暂不计 BFF 自身失败和额外超时,那么页面全部取得结果的概率约为:

text
0.999 × 0.999 × 0.999 ≈ 99.70%

并行调用不代表失败独立;共享数据库故障就会破坏这个假设。并行等待通常取最慢依赖的耗时,成功却仍需要三者都成功。若推荐只是可选内容,可以显式返回“暂无推荐”,避免把它算作整页失败。

配置与密钥不是一回事 ​

配置可以按敏感性和变更方式分类:

类型示例要求
普通部署配置端口、依赖地址、功能参数版本化、可审计、环境覆盖
动态运行配置限流阈值、实验比例有范围校验、回滚和生效观测
密钥数据库口令、签名密钥专用密钥存储、最小权限、轮换
业务数据商品价格、比赛规则走业务模型和审批,不伪装成配置

不要把密钥提交到仓库,也不要因为“动态配置方便”就允许任意运行时修改核心业务规则。配置变更同样需要所有者、验证、审计和回滚。

Kubernetes Secret 的 data 使用 Base64 编码;编码不提供保密性,仍需配置存储加密和访问权限。轮换数据库口令时,还要确认连接池何时重建连接,不能只看配置中心显示“已更新”。动态配置也不保证所有实例同时生效,应记录配置版本,检查每个实例的实际生效状态。

拓扑越短,故障越容易推理 ​

一个入口路径如果是:

text
Gateway → BFF → Aggregator → Domain Service → Internal Proxy → Database

每一跳都会消耗延迟、连接和可用性预算。新增中间层前应说明它承担的稳定职责;只为“以后可能复用”增加代理,会把未来成本提前变成当前故障面。

设计检查表 ​

  • 服务通过稳定名称发现,还是依赖易变实例地址?
  • 就绪与存活是否表达了不同语义?
  • 网关只做边界治理,还是藏有业务流程?
  • BFF 的每个扇出依赖是否有部分失败策略?
  • 配置和密钥是否具有不同的存储、权限与轮换机制?
  • 是否能从入口追踪到所有下游,并传播截止时间与取消?

下一课为这张拓扑增加失败控制:先限制等待,再限制重试,最后限制故障对资源池的占用。

参考资料 ​

Built with VitePress | Software Systems Atlas