跳转到正文
API 网关指南
本文目录

第 93 篇

用 Prometheus 和 Grafana 监控 API 网关:指标、仪表盘与告警

Prometheus 和 Grafana 可以把 API 网关变成重要的观测点,用于了解请求速率、客户端可见错误、延迟、饱和度与上游健康状态。但可靠的方案不只是开放一个 /metrics:还要把抓取链路放在私有网络,控制标签基数,区分网关生成的响应和上游响应,并让仪表盘与告警围绕用户可感知的服务目标工作。

指标展示的是聚合行为。它不能证明应用返回了正确结果,也不能在认证尚未建立时确认调用者身份,更不能取代事件调查所需的日志与链路追踪。

核心要点

  • 默认使用专用的私有指标监听端口,不要把运维数据发布到公共 API 监听端口。
  • 先覆盖速率、错误、耗时、饱和度和上游健康;只有为了回答明确的运维问题时才增加标签。
  • 使用稳定的路由和服务 ID,把名称视为可变的展示信息。
  • 分别观察客户端可见状态、上游状态,以及实际生成响应的组件。
  • Grafana 仪表盘服务于调查,告警服务于行动;Grafana 评估告警规则时无法使用仪表盘变量。
  • 在信任告警前,测试指标缺失、抓取失败、重启、低流量和部分实例丢失。

设计监控链路

1flowchart LR
2    C[客户端] --> G[APISIX 数据面]
3    G --> U[上游服务]
4    P[运维网络中的 Prometheus] -->|抓取私有端点| E[APISIX 指标导出端]
5    E -. 本地网关指标 .-> G
6    P --> R[记录规则与告警规则]
7    P --> D[Grafana 数据源]
8    D --> B[仪表盘]
9    R --> A[Alertmanager 或 Grafana Alerting]
10    A --> O[值班负责人和运行手册]

抓取链路属于运维控制面,可能暴露路由 ID、服务 ID、上游地址、消费者(Consumer)、主机名、流量规模与故障模式。应把它放在受限网络中;环境有要求时增加认证或隧道,并限制能够查询 Prometheus 和 Grafana 的人员。

不要仅凭 consumer、地址或模型标签推断终端用户身份。标签只描述 APISIX 当时把什么信息与请求关联起来;这种关联是否权威,取决于认证方式和可信代理配置。

配置 APISIX 3.19 指标导出端

Apache APISIX 3.19.0 的 prometheus 插件会导出文本格式的指标端点。其默认静态配置会在 127.0.0.1:9091 启用专用导出端,路径为 /apisix/prometheus/metrics。

下面的 config.yaml 片段明确选择了这条路径,并把导出端绑定到一个私有地址占位符:

1plugin_attr:
2  prometheus:
3    export_uri: /apisix/prometheus/metrics
4    metric_prefix: apisix_
5    enable_export_server: true
6    export_addr:
7      ip: 10.0.8.21
8      port: 9091

重载 APISIX 前,应把地址替换为真实私有接口并落实网络策略。当 enable_export_server: true 时(也是默认值),专用导出端会在 export_addr 监听;设为 false 时,专用导出端不监听。APISIX 还说明了通过普通请求监听端口上的 public-api 暴露指标的替代方案,但这会把指标放到公共 API 路径,并增加请求路径的暴露面与开销。只有在访问设计明确时才应采用。

根据所需范围,在对应路由、服务或全局规则上启用插件。下面是一个示意性的路由片段:

1{
2  "id": "orders-read",
3  "uri": "/orders/*",
4  "plugins": {
5    "prometheus": {
6      "prefer_name": false
7    }
8  },
9  "upstream_id": "orders-read"
10}

prefer_name 默认是 false:当对应的路由或服务存在时,APISIX 会为该标签选择其 ID;设为 true 时,则选择已配置的名称。因此,依赖这条路径前应先配置名称,不要假定名称缺失时一定会自动回退到 ID。这些标签还存在实体缺失路径:请求未匹配路由时,路由标签为空;对于内置的 HTTP 状态、延迟和带宽指标,如果没有服务,APISIX 会把已配置的路由主机名写入服务标签。上面的示例只有 upstream_id,没有服务,因此它的服务标签不是服务 ID 或名称。ID 通常更适合关联和历史查询,因为展示名称可能改变;只有组织对名称唯一性和生命周期有明确治理时,名称才会在不破坏查询的前提下提升可读性。这个布尔参数的两条路径都不会改变认证状态,也不会让标签成为可信身份。

让 Prometheus 抓取指标

替换目标地址,并确保 Prometheus 可以访问该私有地址后,下面的 Prometheus 片段可以直接使用:

1scrape_configs:
2  - job_name: apisix-gateway
3    metrics_path: /apisix/prometheus/metrics
4    static_configs:
5      - targets:
6          - 10.0.8.21:9091
7        labels:
8          environment: production
9          gateway_cluster: edge-eu-1

弹性集群应使用服务发现,而不是静态目标,但 environment 与 gateway_cluster 的取值必须有界。检查每个预期目标的 up,并针对实例缺失比例告警;一个导出端健康,并不能证明所有网关实例都在被抓取。

选择能回答运维问题的指标

APISIX 3.19 提供的指标包括:

问题APISIX 指标或标签
客户端最终收到什么状态?apisix_http_status 和 code
响应由谁生成?response_source:apisix、nginx 或 upstream
请求总共耗时多久?apisix_http_latency{type="request"}
等待上游花了多久?apisix_http_latency{type="upstream"}
网关自身开销是多少?apisix_http_latency{type="apisix"}
活跃连接是否接近容量?apisix_nginx_http_current_connections
配置存储是否可达?apisix_etcd_reachable
启用健康检查的上游节点状态如何?apisix_upstream_status
指标存储空间是否即将耗尽?apisix_shared_dict_capacity_bytes 与 apisix_shared_dict_free_space_bytes

经过插件处理和代理错误处理后,客户端状态可能与上游状态不同。网关生成的 429、NGINX 生成的 502 和上游返回的 503 即使都代表失败,也可能由不同团队负责。

在标签基数反过来控制系统之前先治理它

Prometheus 插桩指南指出,每一种标签组合都会形成新的时间序列,消耗内存、CPU、磁盘和网络资源。不要把请求 ID、原始 URL、用户 ID、电子邮件、Token 或其他无界值放进指标标签。

增加标签前,先记录:

  1. 它要回答什么运维问题;
  2. 每个环境最多会出现多少个值;
  3. 由谁清理过期值;
  4. 预计会把时间序列数量放大多少倍;
  5. 日志或链路追踪是否更适合回答这个问题。

APISIX 3.19 的插件元数据可以把部分内置标签值折叠为空字符串,同时保留指标结构。如果不需要按节点、消费者或模型查看明细,就使用这项控制。不要因为可以使用 upstream_addr 就直接增加它;弹性节点变化可能制造大量长期存在的时间序列。

先建立记录查询

下面的 PromQL 是查询示例,不是通用告警阈值。应先根据实际部署中的标签进行验证。

五分钟窗口内,客户端可见的 5xx 比例:

1sum(rate(apisix_http_status{code=~"5.."}[5m]))
2/
3sum(rate(apisix_http_status[5m]))

按路由统计的 p95 请求延迟,单位为毫秒:

1histogram_quantile(
2  0.95,
3  sum by (le, route) (
4    rate(apisix_http_latency_bucket{type="request"}[5m])
5  )
6)

APISIX prometheus-metrics 共享字典的剩余空间比例:

1apisix_shared_dict_free_space_bytes{name="prometheus-metrics"}
2/
3apisix_shared_dict_capacity_bytes{name="prometheus-metrics"}

把昂贵或高频复用的表达式做成记录规则。面板标题和告警说明必须标出单位:APISIX HTTP 延迟直方图使用毫秒,而许多应用和 Prometheus 生态的耗时指标使用秒。

让 Grafana 仪表盘围绕问题组织

Grafana 的 Prometheus 数据源支持 PromQL、告警、记录规则和 exemplar。实用的网关仪表盘应分层展示:

  • 服务总览: 请求速率、成功/错误比例、p50/p95/p99 延迟、被拒流量和 SLO 错误预算消耗;
  • 网关诊断: 响应来源、APISIX 与上游延迟、活跃连接、共享字典容量、配置存储可达性与全实例抓取覆盖;
  • 上游诊断: 健康检查状态、按服务统计的延迟/错误变化,以及基数可控时的节点分布;
  • 变更上下文: 来自另一个可信数据源的部署、配置版本和事件标记。

把仪表盘和数据源配置放进版本控制。Grafana 允许在 UI 中修改通过配置文件供应的仪表盘,但这些修改不会自动写回供应源。必须明确 Git 还是 UI 才是权威来源,避免无声漂移。

针对用户影响和可执行动作告警

Prometheus 告警指南建议围绕症状告警,并避免发出无人可执行的通知。持续的用户可见错误或延迟预算快速消耗,适合呼叫值班人员;容量与组件信号则应进入调查或工单流程,除非它们预示即将发生的用户影响。

每条告警应包含:

  • 受影响的服务、环境和网关集群;
  • 用户可见症状和观测窗口;
  • 正在消耗的 SLO 或容量阈值;
  • 不依赖未解析变量的仪表盘链接;
  • 运行手册和负责团队;
  • 抑制条件与恢复预期。

Grafana 在后端评估告警规则时没有仪表盘变量上下文。使用 $route 或 $cluster 的面板查询,必须改写为包含明确标签匹配器的告警规则,或先做记录规则。告警规则应脱离仪表盘独立测试。

验证失败路径

生产告警启用前,至少测试:

  1. Prometheus 无法访问一个网关导出端;
  2. 整个抓取任务消失;
  3. APISIX 重启并导致计数器重置;
  4. 某条路由没有流量,因此对应序列尚未出现;
  5. 上游返回错误,但 APISIX 仍能处理其他路由;
  6. APISIX 在代理前生成拒绝响应;
  7. 扩缩容或模型发布期间标签基数增长;
  8. Grafana 不可用但 Prometheus 告警评估仍在继续,或相反情况。

使用 absent() 和实例覆盖率时要谨慎:按路由的序列缺失,可能是没有流量、未启用插桩、配置漂移或抓取失败。呼叫值班人员前先用其他信号印证。

监控检查清单

  • 指标端点是否只有预期的运维网络可以访问?
  • 是否明确理解 enable_export_server 在 true 和 false 时的行为?
  • 是否通过 prefer_name 有意识地选择了路由/服务 ID 或名称?
  • 是否禁止或折叠了无界和不必要的标签?
  • 仪表盘能否区分 APISIX、NGINX 与上游产生的响应?
  • 延迟单位和直方图桶是否适合当前 SLO?
  • 告警是否能在没有仪表盘变量的情况下正常评估?
  • 每次呼叫是否包含用户影响、负责人、运行手册和动作?
  • 是否测试了抓取丢失、序列缺失、计数器重置和部分实例失败?
  • 对于指标无法回答的问题,是否有日志与链路追踪可用?

常见问题

APISIX 指标端点应该公开吗?

通常不应该。它会暴露运维细节,也可能给公共请求路径增加工作。优先使用运维私有网络上的专用导出端。

仪表盘应该按路由名称还是路由 ID 分组?

ID 是 APISIX 的默认值,通常也更稳定。只有名称唯一性和改名生命周期得到治理时才使用名称,并通过独立清单把 ID 映射到负责人。

Prometheus 指标可以代替网关日志吗?

不能。指标用于发现聚合趋势;日志和链路追踪提供请求级上下文,而语义正确性还需要应用侧检查。

后续步骤

把这些信号用于 API 网关可靠性工程,通过网关日志分析关联事件,并在日志存储架构中管理长期记录。

编辑本篇文章

获取方案