第 94 篇
API 网关可靠性工程:SLO、故障隔离与事件响应
API7.ai
2026年10月29日
API 网关可靠性并不是“网关进程有多少时间在线”。它指的是网关对用户可感知服务目标的贡献:接纳有效请求、执行必要策略、选择合格上游,并在承诺时间内返回正确响应。
网关可以隔离部分故障,也能提供有用证据,但它无法保证应用正确性,不能让不安全的重试变得安全,也不能恢复已经失去容量或数据的依赖。可靠性工程要先定义用户旅程和故障归属,再选择能在压力下守住契约的控制措施。
核心要点
- 先从用户结果定义 SLI,再选择最容易采集的网关指标。
- 区分网关可用性、策略依赖、上游服务与端到端正确性故障。
- 健康检查、重试、熔断、负载削减和流量迁移是不同控制手段。
- 对每个外部策略和状态依赖,都要记录放行与拒绝的失败行为。
- 用错误预算治理发布与恢复,而不是把它当成一次性消耗剩余故障额度的许可。
- 事件期间要保留配置版本、响应来源、尝试次数和降级模式证据。
从面向用户的可靠性契约开始
Google SRE 的 SLO 指南建议从用户关心的结果反推,并明确目标如何测量、在什么条件下有效。对经过网关的订单查询,可以这样定义:
- 良好事件: 在支持的请求大小范围内,已经认证和授权的
GET /orders/{id}请求,在 500 ms 内返回应用确认有效的响应; - 有效总体: 生产环境请求,不包含批准的合成测试和有记录的客户端主动取消;
- 目标: 28 天滚动窗口内 99.9% 为良好事件;
- 测量点: 网关面向客户端的结果,加上应用正确性信号。
网关可以测量状态码与延迟,但 HTTP 200 本身不能证明订单结果正确。反过来,网关返回 429 可能是有意削减负载,而不是上游故障;除非产品契约明确排除或单独预算这一准入类型,否则它仍然会影响用户。
不要让无关工作负载共用一个 SLO。交互式读取、异步提交、流式响应和管理 API 的延迟与正确性预期各不相同。
增加控制前先划分故障归属
1flowchart LR
2 C[客户端] --> E[边缘层或负载均衡器]
3 E --> G[网关数据面]
4 G --> P[策略与配额依赖]
5 G --> U[上游池]
6 U --> D[应用依赖]
7 CP[网关控制面] -. 配置流 .-> G
8 G -. 指标、日志、链路追踪 .-> O[可观测系统]对每条箭头,都要记录依赖变慢、不可用、过期或相互矛盾时会发生什么。数据面可能在控制面故障期间继续使用最后一份有效配置,但这是以变更新鲜度换取请求连续性。配额存储故障时,可以选择拒绝以保住权益边界,也可以选择放行以保住可用性,没有一种选择适用于所有场景。
一张实用的故障表需要足够明确:
| 依赖 | 主要负责人 | 用户可见故障 | 预期降级模式 | 最长持续时间 |
|---|---|---|---|---|
| 网关实例 | 平台团队 | 连接失败或 5xx | 从边缘流量池移除实例 | 探测与连接排空预算 |
| 策略服务 | 安全/平台团队 | 拒绝、绕过或延迟 | 拒绝,或使用有范围的缓存决策 | 按策略确定 |
| 上游节点 | 服务负责人 | 连接错误、超时、5xx | 若可安全重放,选择另一个合格节点 | 请求截止时间 |
| 配置存储 | 平台团队 | 配置过期或无法变更 | 使用最后一份有效配置 | 配置陈旧预算 |
| 遥测后端 | 可观测团队 | 证据丢失或延迟 | 有界本地缓冲或丢弃策略 | 保留预算 |
“继续服务”还不够,还要说明哪些策略、配置或证据可能过期或缺失。
让控制手段匹配故障
| 控制 | 主要用途 | 它无法证明什么 |
|---|---|---|
| 主动健康检查 | 通过合成探测发现节点,并允许恢复探测 | 每个操作和依赖都健康 |
| 被动健康检查 | 从已代理请求结果中学习 | 不再接收流量的节点已经恢复 |
| 重试 | 对可安全重放的工作再做一次有界尝试 | 第一次尝试没有产生效果 |
| 熔断器 | 在满足配置的故障证据后停止或减少调用 | 根因或语义正确性 |
| 速率/并发限制 | 限制接纳的工作量 | 公平性或下游一定成功 |
| 流量拆分 | 在版本或流量池之间迁移受控份额 | 每个短窗口都达到精确比例 |
| 缓存或陈旧响应 | 在依赖失败时维持部分读取 | 数据新鲜度或对每种资源都适用 |
把所有控制叠加起来,反而可能放大故障。客户端、网关、服务网格和应用各自重试,会把工作量成倍放大。熔断器快速返回,可能让上游看起来负载变轻,但用户仍然失败。陈旧缓存可以保住读取,却可能违反新鲜度或撤销要求。
使用 APISIX 健康检查时要关注流量池边界
Apache APISIX 3.19.0 支持主动和被动上游健康检查。主动检查使用 HTTP、HTTPS 或 TCP 探测;被动检查则根据已代理请求结果分类。
被动检查本身无法把不健康节点重新标记为健康,因为该节点已经不再接收请求。需要自动发现恢复时,应与主动检查结合使用。APISIX 还记录了流量池层面的放行边界:如果无法选择任何健康节点,它仍会继续访问上游。这样不会把健康分类变成绝对的流量开关,却可能把请求发给正在失败的流量池。
应判断这一行为是否符合服务契约。如果联系不健康节点比返回受控网关响应更糟,就增加明确的准入或熔断策略,并测试“健康节点耗尽”路径。不要宣称启用健康检查后,流量一定只会到达健康节点。
探测设计同样重要。浅层 TCP 探测只能说明进程接受连接,即使数据库已经不可用;深层探测则可能制造负载,或因为一个非关键依赖把整个服务移出。应分别使用存活、就绪和诊断信号,并让路由探测保持有界。
把熔断器当成路由策略,而不是根因诊断
APISIX 3.19.0 的 api-breaker 插件会根据配置的上游响应状态和失败次数判定故障,并在熔断器打开时返回配置的响应。它会按指数间隔尝试恢复,最长不超过 max_breaker_sec,并在达到指定健康成功次数后关闭熔断器。
下面的片段有意给出具体值,而不是依赖默认值:
1{
2 "api-breaker": {
3 "break_response_code": 503,
4 "break_response_body": "Service temporarily unavailable",
5 "max_breaker_sec": 30,
6 "unhealthy": {
7 "http_statuses": [500, 502, 503, 504],
8 "failures": 5
9 },
10 "healthy": {
11 "http_statuses": [200, 204],
12 "successes": 2
13 }
14 }
15}这只是插件片段,不是完整路由。它用 HTTP 状态作为证据,不会检查应用正确性,无法区分所有故障原因,也不能替代每节点健康检查。状态码应根据应用语义选择:一个无效输入导致的 500 不一定应该让整个服务退出,而一次探测成功也不代表原操作已经恢复。
熔断器打开时返回的合成 503 由网关生成。遥测必须保留响应来源,避免值班人员把它误归因于上游。
在系统崩溃前削减负载
当需求超过安全容量时,尽早做有界拒绝,往往比让队列持续增长、最终所有请求都超时更好。需要定义:
- 要保护的资源:连接、网关 Worker、上游并发、数据库容量或模型队列;
- 准入键及其可信来源;
- 优先级类别和防止饥饿的措施;
- 拒绝状态与重试指导;
- 最大队列和截止时间;
- 结束降级模式的信号。
速率限制保护时间窗口内的速率,并发限制保护同时进行的工作。除非策略提供信息,否则两者都不了解业务优先级。调用方提供的优先级请求头并不权威,只有认证身份和服务端权益把它映射到某个类别后,才能用于策略。
用错误预算治理变更
错误预算是 SLO 隐含的失败额度,不是可以随意花掉的中断时间。应根据消耗速率和剩余预算决定是否:
- 继续或暂停发布;
- 降低金丝雀权重;
- 关闭成本较高的可选插件;
- 停止功能开发并修复可靠性;
- 启用有记录的降级模式。
APISIX 3.19.0 的 traffic-split 插件可以把流量导向加权上游。其文档提醒,由于使用加权轮询,尤其在状态重置后,实际比例可能不够精确。权重代表路由意图,不保证每个短窗口都达到精确百分比。
应在同一个有效请求总体上比较金丝雀与基线。晋级条件要覆盖用户可见错误、延迟、饱和度和语义检查,网关进程健康远远不够。
把事件证据内建到网关路径
事件期间,应能快速回答:
- 哪条用户旅程和哪个 SLO 正在快速消耗预算?
- 哪些网关集群、路由、服务和版本受到影响?
- 响应由 APISIX、NGINX 还是上游生成?
- 延迟有多少发生在网关,有多少是在等待上游?
- 哪种健康、熔断、重试、缓存或负载削减状态正在生效?
- 一个客户端请求触发了多少次上游尝试?
- 事件前是否发生过配置、部署、证书、策略或依赖变更?
- 缓解措施是否仍满足安全、一致性和证据义务?
关联标识符应便于串联事件,但不能被当成身份。如果调用方可以提供或保留请求 ID,那么它只能作为关联上下文,而不是谁执行了操作的证明。
测试可靠性契约
应进行受控演练,覆盖:
- 一个网关实例失败,其他实例仍健康;
- 控制面不可用与配置过期;
- 上游变慢、拒绝连接、连接重置和应用错误;
- 所有上游节点都被判定不健康;
- 策略和配额依赖按设计放行或拒绝;
- 修改操作在可能已经生效后超时;
- 用户可见事件期间,指标、日志和链路追踪丢失;
- 实时流量下的金丝雀回归和回滚;
- 恢复时不引发流量激增或重试风暴。
断言应覆盖端到端不变量:最大尝试次数、最大延迟、允许的降级行为、配置年龄,以及不会产生重复效果。如果故障阶段可能合理地返回不同状态码,就不要只断言一个固定状态码。
可靠性工程检查清单
- 每类工作负载是否都有面向用户的 SLI、目标、窗口和有效总体?
- 应用正确性与网关状态是否分开测量?
- 每个依赖和降级模式是否都有明确负责人?
- 健康检查、重试、熔断和负载削减是否承担不同职责?
- APISIX 在没有健康节点时的放行行为是否经过测试并可接受?
- 策略依赖是否明确规定放行或拒绝,并设置时间边界?
- 重试是否仅用于可安全重放、且能在剩余截止时间内完成的工作?
- 发布门槛是否基于金丝雀实测结果,而不是只看配置权重?
- 遥测能否区分网关、NGINX 和上游生成的响应?
- 事件手册是否仍保留必要的安全与审计控制?
常见问题
高可用网关能保证 API 可靠吗?
不能。它只是消除一种基础设施故障模式。端到端可靠性还取决于策略服务、上游、数据存储、网络、客户端和语义正确性。
策略依赖失败时,APISIX 是否应该拒绝请求?
取决于策略。授权和权益检查往往需要拒绝,可选的上下文增强则可能安全放行。应为每个依赖记录决策、范围、持续时间与告警。
健康检查和熔断器可以互换吗?
不能。健康检查根据节点可达性或响应给节点分类;熔断器则在配置作用域内按照故障策略停止调用。两者观察的证据和恢复行为都不同。
后续步骤
使用 Prometheus 和 Grafana 网关监控为契约建立指标,通过安全的超时与重试策略限制尝试次数,并把容量信号接入弹性网关扩缩容。