适用场景

本文适用于 Prometheus 已经配置了 scrape_configs,但在 Targets 页面看到目标实例显示 DOWN,或者 PromQL 查询 up{job="xxx"} == 0 的场景。常见对象包括 node_exporter、应用自暴露的 /metrics、Kubernetes ServiceMonitor、Nginx/Redis/MySQL exporter 等。

这类问题的核心不是“指标是否正常”,而是 Prometheus 到目标端点的抓取链路是否打通。排查时要按链路拆开看:服务发现是否发现目标、网络是否可达、HTTP 响应是否正确、鉴权和 TLS 是否匹配、抓取超时和指标体积是否合理。

现象描述

典型现象包括:

  • Prometheus Web UI 的 Status -> Targets 中实例状态为 DOWN
  • 查询 up{job="node"} 返回 0
  • Alerts 中出现 InstanceDownTargetDown 或自定义抓取失败告警。
  • Grafana 面板突然断点,很多指标显示 No data
  • Prometheus 日志中出现 context deadline exceededconnection refusedserver returned HTTP status 401x509: certificate signed by unknown authority 等错误。

up 是 Prometheus 每次抓取自动生成的指标:

up{job="node", instance="10.0.1.12:9100"}

返回值含义:

  • 1:本轮抓取成功。
  • 0:目标被发现了,但本轮抓取失败。
  • 没有序列:目标没有被发现,或者标签条件写错。

因此,先确认是 up=0 还是根本没有 up 序列,这一步能避免把服务发现问题误判成网络问题。

可能原因

常见原因可以分成几类:

  1. 目标进程未启动,端口没有监听。
  2. Prometheus 到目标端口的网络不通,例如安全组、防火墙、NetworkPolicy、路由问题。
  3. metrics_pathscheme、端口或服务发现标签配置错误。
  4. 目标端返回非 2xx 状态码,例如 401、403、404、500。
  5. TLS 证书、SNI、CA、客户端证书配置不匹配。
  6. 指标接口太慢或指标量太大,超过 scrape_timeout
  7. exporter 本身卡住,例如采集磁盘、数据库、外部 API 时阻塞。
  8. Kubernetes 场景中 Service、Endpoints、Pod label、ServiceMonitor selector 不匹配。

排查思路

1. 先看 Targets 页面给出的错误

Prometheus 的 Targets 页面通常会直接给出最近一次错误,优先看以下字段:

  • State:目标状态,UPDOWN
  • Endpoint:Prometheus 实际抓取的 URL。
  • Last Scrape:最近抓取时间。
  • Scrape Duration:本次抓取耗时。
  • Error:失败原因。

也可以通过 PromQL 快速列出失败目标:

up == 0

如果只想看某个 job:

up{job="node"} == 0

如果目标没有任何 up 序列,说明它可能没有被 Prometheus 发现。此时应转去检查 scrape_configs、服务发现、ServiceMonitor 或 relabel 规则。

2. 在 Prometheus 机器上验证端口连通

不要只在自己的电脑上 curl 目标地址,要在 Prometheus 所在机器或 Pod 内验证,因为网络路径不同。

Linux 主机部署时:

nc -vz 10.0.1.12 9100
curl -v --max-time 5 http://10.0.1.12:9100/metrics

Kubernetes 部署时:

kubectl -n monitoring exec -it deploy/prometheus-server -- sh

进入容器后再测试:

wget -S -O- --timeout=5 http://node-exporter.monitoring.svc:9100/metrics

重点看三类结果:

  • connection refused:IP 可达但端口没有监听,优先查目标进程。
  • connection timed out:网络链路不通,优先查防火墙、安全组、NetworkPolicy、路由。
  • HTTP 返回 401、403、404、500:网络已通,继续查路径、鉴权或目标服务。

3. 检查目标端口是否监听

在目标机器上执行:

ss -lntp | grep ':9100'
systemctl status node_exporter --no-pager
journalctl -u node_exporter -n 80 --no-pager

关键字段:

  • LISTEN 后面的本地地址如果是 127.0.0.1:9100,说明只监听本机,远端 Prometheus 无法访问。
  • 0.0.0.0:9100 或指定内网 IP 通常才适合被 Prometheus 抓取。
  • journalctl 中如果有权限错误、collector 初始化失败、端口占用,需要先修复 exporter。

如果进程只监听本机地址,应调整启动参数。例如 node_exporter:

--web.listen-address=:9100

修改 systemd 后需要重载并重启:

systemctl daemon-reload
systemctl restart node_exporter
systemctl status node_exporter --no-pager

4. 核对 Prometheus 抓取配置

静态配置示例:

scrape_configs:
  - job_name: node
    scrape_interval: 30s
    scrape_timeout: 10s
    metrics_path: /metrics
    scheme: http
    static_configs:
      - targets:
          - 10.0.1.12:9100
          - 10.0.1.13:9100

检查点:

  • targets 必须包含端口,不能只写 IP。
  • metrics_path 要和应用实际暴露路径一致。
  • scheme 要区分 httphttps
  • scrape_timeout 必须小于或等于 scrape_interval
  • 修改配置后要 reload Prometheus,而不是只改文件。

校验配置文件:

promtool check config /etc/prometheus/prometheus.yml

重载配置:

curl -X POST http://127.0.0.1:9090/-/reload

如果没有开启 lifecycle API,则需要重启 Prometheus:

systemctl restart prometheus

5. 处理 HTTP 状态码错误

如果 Targets 页面显示 server returned HTTP status 404,通常是路径错误:

curl -i http://10.0.1.12:8080/metrics
curl -i http://10.0.1.12:8080/actuator/prometheus

很多 Spring Boot 应用的 Prometheus 指标路径是:

/actuator/prometheus

对应配置应写成:

scrape_configs:
  - job_name: spring-app
    metrics_path: /actuator/prometheus
    static_configs:
      - targets:
          - 10.0.2.21:8080

如果返回 401 或 403,说明目标端需要鉴权。Basic Auth 示例:

scrape_configs:
  - job_name: secure-app
    metrics_path: /metrics
    static_configs:
      - targets:
          - 10.0.2.22:8080
    basic_auth:
      username: prometheus
      password_file: /etc/prometheus/secrets/metrics_password

不要把密码直接写进 Git 仓库。生产环境建议使用 password_file、Kubernetes Secret 或配置管理系统下发。

6. 处理 TLS 证书错误

如果错误里有 x509,说明 TLS 校验失败。先确认目标证书:

openssl s_client -connect metrics.example.com:443 -servername metrics.example.com </dev/null

Prometheus 配置可以指定 CA:

scrape_configs:
  - job_name: https-app
    scheme: https
    static_configs:
      - targets:
          - metrics.example.com:443
    tls_config:
      ca_file: /etc/prometheus/certs/ca.pem
      server_name: metrics.example.com

临时排查可以使用:

tls_config:
  insecure_skip_verify: true

但这只能作为短期验证手段,不建议长期使用。正式修复应补齐可信 CA、正确的证书链和匹配的 SNI。

7. 判断是否抓取超时

如果错误是 context deadline exceeded,先看抓取耗时和样本数量:

scrape_duration_seconds{job="app"}
scrape_samples_scraped{job="app"}

也可以看最近失败原因:

scrape_timeout_seconds{job="app"}

处理思路:

  • 如果接口偶尔慢,检查应用或 exporter 是否在抓取时访问慢资源。
  • 如果指标量突然增大,检查是否出现高基数标签,例如 user_idrequest_id、订单号。
  • 如果确实需要更长时间,适当提高 scrape_timeoutscrape_interval,但不要把超时简单拉到很大。

示例配置:

scrape_configs:
  - job_name: heavy-exporter
    scrape_interval: 60s
    scrape_timeout: 20s
    static_configs:
      - targets:
          - 10.0.3.30:9200

如果 scrape_samples_scraped 持续异常增长,应优先减少指标基数,而不是只增加 Prometheus 资源。

Kubernetes 场景定位示例

假设 ServiceMonitor 创建后,Prometheus 没有抓到目标。

先看 Service 是否有 Endpoints:

kubectl -n app get svc my-app
kubectl -n app get endpoints my-app -o wide

如果 Endpoints 为空,说明 Service selector 没有匹配到 Pod:

kubectl -n app get svc my-app -o yaml
kubectl -n app get pod --show-labels

检查 ServiceMonitor selector:

kubectl -n monitoring get servicemonitor my-app -o yaml

重点看:

  • spec.selector.matchLabels 是否匹配 Service 标签。
  • spec.namespaceSelector 是否包含业务命名空间。
  • spec.endpoints[].port 是否写的是 Service port 的名称,而不是端口数字。

Service 示例:

apiVersion: v1
kind: Service
metadata:
  name: my-app
  namespace: app
  labels:
    app: my-app
spec:
  selector:
    app: my-app
  ports:
    - name: metrics
      port: 8080
      targetPort: 8080

ServiceMonitor 示例:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: my-app
  namespace: monitoring
spec:
  namespaceSelector:
    matchNames:
      - app
  selector:
    matchLabels:
      app: my-app
  endpoints:
    - port: metrics
      path: /metrics
      interval: 30s

这里的 port: metrics 必须对应 Service 里的端口名称 name: metrics

修复方案

根据错误类型选择修复动作:

  • 端口未监听:启动 exporter 或修复 systemd 配置。
  • 只监听 127.0.0.1:改为监听内网地址或 0.0.0.0
  • 网络超时:放通安全组、防火墙、NetworkPolicy 或修复路由。
  • 404:修正 metrics_path
  • 401/403:配置 Basic Auth、Bearer Token 或目标端白名单。
  • TLS 报错:补齐 CA、证书链、SNI 或客户端证书。
  • 抓取超时:优化 exporter、降低指标基数,必要时调整抓取间隔和超时。
  • Kubernetes 未发现目标:修正 Service selector、ServiceMonitor selector、命名空间选择器和端口名称。

修复后用三步确认:

up{job="目标job"}
scrape_duration_seconds{job="目标job"}
scrape_samples_scraped{job="目标job"}

确认 up 变成 1,抓取耗时低于 scrape_timeout,样本数量稳定,没有明显突增。

预防措施

  1. 为所有关键 job 配置 up == 0 告警,并设置合理的 for 时间,避免短暂重启造成误报。
  2. scrape_duration_seconds / scrape_timeout_seconds 配置接近超时告警,提前发现抓取变慢。
  3. scrape_samples_scraped 建立基线,发现指标量异常增长及时处理。
  4. 应用发布时把 /metrics 纳入健康检查清单,确认路径、鉴权和 TLS 配置。
  5. Kubernetes 中统一 Service 端口命名,例如固定使用 metrics,减少 ServiceMonitor 配置错误。
  6. 不要在指标标签里放用户 ID、请求 ID、订单号等高基数字段。
  7. Prometheus 配置变更前执行 promtool check config,避免配置错误导致整段抓取失效。

总结

up=0 的排查要先判断目标是否被发现,再沿着 Prometheus 到目标端点的链路逐层确认。Targets 页面里的错误信息通常已经指出方向:拒绝连接查进程和监听地址,超时查网络链路,404 查路径,401/403 查鉴权,x509 查证书,deadline exceeded 查耗时和指标量。

处理这类问题不要一开始就改告警规则或扩大超时时间。正确做法是先恢复抓取链路,再评估是否需要优化 exporter、收敛指标基数、调整抓取周期和补充预防性告警。