Prometheus 会主动请求每个已配置目标的 HTTP 指标端点。目标负责暴露观测值,采集器决定抓取时刻、解析响应并保存样本。这种安排让采集故障能够从采集器一侧被看见,但不能保证端点一定可达、所有预期目标都被发现,也不能保证用户的登录或下单流程正常。理解这些边界,才能把采集结果转换成准确的告警和排查动作。
一个任务包含多个独立抓取的实例
任务通常把用途相同的目标组织在一起,例如一组接口服务副本。每个目标仍是独立实例,具有自己的抓取结果。常见的 job 与 instance 标签标识这层上下文,最终标签也可能经过重新标记而改变。服务发现提供候选目标,抓取配置再决定实际访问的端点、协议、周期、超时和认证方式。因此,目标没有被发现与目标已经配置但抓取失败,是两类不同的问题。
采集器必须能够连接目标。虽然导出器不需要主动向采集器上传指标,目标仍然需要允许经过授权的采集器访问其入站端口。网络策略、证书身份、认证凭据与路由不会因为采用拉取模式而消失。拉取只是改变连接由哪一方发起,不能把任意导出器变成可以直接暴露在公网的安全接口。部署时要从采集器所在网络检查这条路径。
准确理解系统生成的指标
对于已配置的实例,Prometheus 会生成 up 指标,抓取成功时为一,失败时为零。它是指标名称,不是所谓的 up 标签。抓取耗时与样本数量则补充了采集质量的证据。导出器可能在后端数据库不可用时仍返回合法响应,也可能漏掉一项重要业务指标,因此即使 up 为一,也不能推导后端依赖和全部业务观测都正常。
这些进一步的问题应由应用结果指标、导出器专门提供的依赖状态,以及实际业务探测回答。反过来,up=0 描述的是采集失败,监控网络故障可能使它变为零,而用户请求仍然成功。告警措辞应写清采集目标与错误证据,避免让响应人员把所有监控链路问题直接当成客户故障。业务影响仍需要另一组证据确认。
指标重新标记不会应用于 up 这类自动生成序列。因此,即使过滤掉了全部业务样本,也可能仍然看到抓取成功。调整过滤规则时,应把预期指标族或样本量纳入验收,分清主动丢弃观测与导出器故障。一个绿色采集指标不能证明过滤后的业务数据仍满足面板和告警所需的契约。
坏掉的样子
连接被拒绝、请求超时、证书校验失败或导出格式无效,都可能让抓取失败。先查看目标的最近抓取错误,再决定需要调整什么。延长周期无法修复错误端口;增大超时可能让缓慢的导出器看起来恢复,却不会消除它的执行成本。采集变贵时还应检查输出序列数量和响应大小,确认是否新增了不必要的标签组合或昂贵查询。抓取超时不能超过配置周期,缩短周期前则应评估导出器负载。更快的轮询可能成倍增加导出器对数据库的查询次数,却不会降低每次查询的成本。
从服务发现中移除的目标,与继续存在但返回零的目标不同。前者的对应序列之后可能不再出现在即时查询中,所以把全站 up 求和,并不能证明所有预期实例仍然存在。需要完整性保证时,应把发现结果与实际部署清单对照。单独请求一次 /metrics 成功,同样不能代替登录、支付或订单提交的功能验证。
快速验证
把下面程序保存为 pull.py,在 Docker 可用的环境执行 python3 pull.py。程序使用 prom/prometheus:v3.5.1,如果本机尚未缓存镜像,首次运行需要从镜像仓库下载。实验只创建一个一次性容器,让其中的 Prometheus 抓取自己的回环端点,以及回环地址上没有服务监听的端口。它不发布宿主机端口,容器也无法访问外部网络。
import json
import subprocess
import uuid
# Requires Docker and the public Prometheus 3.5.1 image.
# All HTTP traffic stays on loopback inside one disposable container.
script = r"""set -eu
cat > /tmp/prom.yml <<'CONFIG'
global:
scrape_interval: 1s
scrape_timeout: 500ms
scrape_configs:
- job_name: self
static_configs:
- targets: ['127.0.0.1:9090']
- job_name: refused
static_configs:
- targets: ['127.0.0.1:1']
CONFIG
/bin/prometheus --config.file=/tmp/prom.yml --storage.tsdb.path=/tmp/data \
--web.listen-address=127.0.0.1:9090 > /tmp/prom.log 2>&1 &
for attempt in $(seq 1 30); do
if wget -qO /tmp/ready.json 'http://127.0.0.1:9090/api/v1/query?query=count%28up%29%20%3D%3D%202%20and%20sum%28up%29%20%3D%3D%201'; then
if grep -q '"status":"success"' /tmp/ready.json && ! grep -q '"result":\[\]' /tmp/ready.json; then
wget -qO- 'http://127.0.0.1:9090/api/v1/query?query=up'
exit 0
fi
fi
sleep 1
done
cat /tmp/prom.log >&2
exit 1
"""
name = "xbcatm-prom-live-" + uuid.uuid4().hex[:12]
try:
result = subprocess.run(
["docker", "run", "--rm", "--name", name, "--network", "none", "-i",
"--entrypoint", "/bin/sh", "prom/prometheus:v3.5.1", "-s"],
input=script, text=True, capture_output=True, timeout=45,
)
finally:
subprocess.run(["docker", "rm", "-f", name],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if result.returncode:
raise RuntimeError(result.stderr or result.stdout)
payload = json.loads(result.stdout)
assert payload["status"] == "success"
values = {item["metric"]["job"]: float(item["value"][1])
for item in payload["data"]["result"]}
assert values == {"self": 1.0, "refused": 0.0}, values
print(json.dumps({"up_by_job": values, "scrape_reachability_only": True}, indent=2))
结果应当包含 self: 1.0 和 refused: 0.0。程序等待两个目标都有抓取结果,再通过查询接口进行断言,因此不会把启动期间数据库暂时为空误判成配置失败。退出清理仅针对本次随机命名的容器,不涉及其他容器。这个结果证明真实采集器可以区分成功抓取与连接拒绝;它没有测试业务功能,也没有证明服务发现清单完整。
让结果指向具体排查动作
实际故障中,先定位失败实例并阅读抓取错误,再从采集器的网络环境检查连接路径。能够拿到响应时,应核对格式、内容类型和导出器依赖状态,而不是只看端口是否开放。复制诊断结果时要去掉凭据。恢复后同时确认 up 与面板实际使用的业务序列:前者恢复不代表后者一定重新出现,遗漏指标仍可能让面板显示空白。
本轮没有修改此运行实验,也没有重新执行。文中的预期输出和此前记录的观察,与本轮执行证据分别保留,不能据此声称真实集成已经再次通过。
来源
- Prometheus: jobs and instances,抓取生成指标与目标身份,已核验 2026-10-15。
- Prometheus: configuration,抓取周期、超时和目标配置,已核验 2026-10-15。
- Prometheus: HTTP API,即时查询的响应格式,已核验 2026-10-15。