零基础搞懂监控工具:从架构思维到实战落地
作者说:我写这篇教程,是因为五年前我刚入行时,被线上故障搞得焦头烂额,却连日志都不知道去哪找。那时候我就想,如果有人能早点告诉我"监控到底是个什么东西",我大概能少掉几根头发。今天,我用最直白的话,把这件事讲清楚。
一、监控工具到底是什么?
我当初学的时候,最大的困惑不是"怎么用 Prometheus",而是"为什么要用它"。
打个比方:你开了一家餐厅,你不可能只坐在收银台等顾客投诉菜不好吃。你会在厨房里装温度计、在冰柜里放传感器、在出菜口装摄像头、在门口放计数器。这些东西加在一起,就是"监控"。
监控工具,就是给你的软件系统装上"温度计"和"摄像头"。
它回答三个核心问题:
| 问题 | 对应监控维度 | 举例 |
|---|---|---|
| 系统现在健不健康? | 健康检查 / 存活探针 | 服务是否在线、端口是否通 |
| 系统跑得慢不慢? | 性能指标 | 接口响应时间、QPS、CPU使用率 |
| 哪里出了问题? | 日志 / 链路追踪 | 错误日志、请求在哪个环节超时 |
从架构设计的角度来看,监控不是一个"附加功能",它是系统的神经系统。没有监控的系统,就像蒙着眼睛开车——能跑,但随时可能撞墙。
二、监控工具的架构全景
在动手之前,我们先在脑子里画一张图。一个完整的监控体系,通常由四层组成:
┌─────────────────────────────────────────────────────┐
│ 展示层(Grafana) │
│ 仪表盘、告警规则、可视化 │
├─────────────────────────────────────────────────────┤
│ 存储与查询层 │
│ Prometheus / InfluxDB / Elasticsearch │
├─────────────────────────────────────────────────────┤
│ 采集与传输层 │
│ Exporter / Telegraf / Filebeat / OTel Collector │
├─────────────────────────────────────────────────────┤
│ 数据源(你的应用) │
│ 业务代码 / 中间件 / 操作系统 / 数据库 │
└─────────────────────────────────────────────────────┘
我用一个表格把每一层的职责说清楚:
| 层级 | 职责 | 常见工具 | 类比 |
|---|---|---|---|
| 数据源 | 产生原始数据 | 你的Java/Python/Go应用 | 厨房里的温度计 |
| 采集层 | 把数据拉走或推走 | Prometheus Exporter、Fluentd | 服务员把数据抄到本子上 |
| 存储层 | 把数据存起来,支持查询 | Prometheus、InfluxDB | 档案柜 |
| 展示层 | 把数据画成图表、触发告警 | Grafana、Alertmanager | 老板看的大屏 |
这里有一个新手常问的问题:Prometheus 和 Grafana 是什么关系?
简单说:Prometheus 负责"存"和"查",Grafana 负责"画"。Prometheus 是仓库管理员,Grafana 是展示设计师。它们是两个独立的工具,但经常一起用。
三、环境准备
我们用一个最小可运行的环境来上手。你需要准备:
- 一台 Linux 机器(CentOS 7+ / Ubuntu 18+),或者用 Docker
- Docker 和 Docker Compose(推荐用 Docker,省去安装的痛苦)
- 一个能跑起来的小 Web 应用(后面我会给你一个 Python 示例)
我当初学的时候,在 CentOS 上手动装 Prometheus 装了两天,配置文件写错一个缩进就报错。后来发现用 Docker 十分钟就搞定了。所以,新手请务必用 Docker。
3.1 创建项目目录
mkdir monitoring-demo
cd monitoring-demo
3.2 编写 docker-compose.yml
这个文件会帮我们一键启动 Prometheus 和 Grafana:
version: '3.8'
services:
prometheus:
image: prom/prometheus:v2.47.0
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
grafana:
image: grafana/grafana:10.1.0
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123
volumes:
- grafana-data:/var/lib/grafana
volumes:
grafana-data:
3.3 编写 Prometheus 配置文件
创建 prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'my-app'
static_configs:
- targets: ['host.docker.internal:8000']
这段配置的意思是:每隔 15 秒,去 host.docker.internal:8000 的 /metrics 端点拉一次数据。host.docker.internal 是 Docker 里访问宿主机的特殊域名。
四、核心概念:用最简单的话讲清楚
4.1 指标(Metric)是什么?
指标就是监控里的"数据点"。它有三个要素:
- 指标名:比如
http_request_duration_seconds - 标签(Label):用来区分维度,比如
method="GET"、status="200" - 值:当前的数值
举个例子:
http_request_duration_seconds{method="GET", path="/api/users", status="200"} 0.035
这行数据的意思是:GET 请求 /api/users 接口、返回 200 状态码的耗时是 0.035 秒。
4.2 四种指标类型
Prometheus 定义了四种指标类型,我用一个表格来对比:
| 类型 | 特点 | 适用场景 | 举例 |
|---|---|---|---|
| Counter | 只增不减 | 累计次数 | 总请求数、错误总数 |
| Gauge | 可增可减 | 瞬时值 | 当前内存使用量、在线人数 |
| Histogram | 分桶统计分布 | 耗时分布 | 请求耗时的百分位 |
| Summary | 客户端计算分位 | 耗时分布 | 请求耗时的 P99 |
我当初学的时候,Counter 和 Gauge 老搞混。后来记住一句话:能回退的是 Gauge,不能回退的是 Counter。比如内存用量可以升可以降,是 Gauge;总请求数只能往上加,是 Counter。
4.3 Pull 模型 vs Push 模型
这是 Prometheus 架构设计里最核心的一个决策。
Pull 模型(Prometheus 的方式):Prometheus 主动去目标机器上拉数据。
Prometheus ──── 请求 /metrics ────> 你的应用
<─────── 返回指标数据 ───────────
Push 模型(传统方式):你的应用主动把数据推给监控中心。
你的应用 ──── 推送指标数据 ────> 监控中心
为什么 Prometheus 选 Pull?因为 Pull 模型有几个好处:
- 你能知道目标是不是活着——拉不到数据,说明目标挂了
- 配置集中管理——在 Prometheus 端配置要监控谁,而不是在每个应用里配置推给谁
- 调试方便——你可以手动
curl目标的/metrics端点看数据对不对
五、实战项目:给你的 Python 应用加上监控
我们用一个 Flask 应用来演示。这个应用有两个接口:一个正常接口,一个偶尔超时的接口。
5.1 安装依赖
pip install flask prometheus_client
5.2 编写应用代码
创建 app.py:
import time
import random
from flask import Flask, jsonify
from prometheus_client import Counter, Gauge, Histogram, generate_latest
app = Flask(__name__)
# 定义指标
REQUEST_COUNT = Counter(
'http_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
)
REQUEST_DURATION = Histogram(
'http_request_duration_seconds',
'HTTP request duration in seconds',
['method', 'endpoint'],
buckets=[0.01, 0.05, 0.1, 0.5, 1.0, 5.0]
)
ONLINE_USERS = Gauge(
'online_users',
'Number of online users'
)
# 模拟在线用户数波动
ONLINE_USERS.set(42)
@app.route('/api/users')
def get_users():
start_time = time.time()
# 模拟业务逻辑
time.sleep(0.02)
# 记录指标
REQUEST_COUNT.labels(method='GET', endpoint='/api/users', status='200').inc()
REQUEST_DURATION.labels(method='GET', endpoint='/api/users').observe(time.time() - start_time)
return jsonify({"users": ["Alice", "Bob", "Charlie"]})
@app.route('/api/slow')
def slow_endpoint():
start_time = time.time()
# 模拟偶尔超时
delay = random.uniform(0.01, 2.0)
time.sleep(delay)
status = '200' if delay < 1.0 else '504'
REQUEST_COUNT.labels(method='GET', endpoint='/api/slow', status=status).inc()
REQUEST_DURATION.labels(method='GET', endpoint='/api/slow').observe(time.time() - start_time)
if delay >= 1.0:
return jsonify({"error": "timeout"}), 504
return jsonify({"result": "ok", "delay": round(delay, 3)})
@app.route('/metrics')
def metrics():
return generate_latest()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
5.3 代码解读
这段代码做了三件事:
- 定义了三个指标:
REQUEST_COUNT(计数器)、REQUEST_DURATION(直方图)、ONLINE_USERS(仪表盘) - 在业务逻辑中埋点:每次请求进来,计数器加一,直方图记录耗时
- 暴露
/metrics端点:Prometheus 来拉数据时,就访问这个端点
5.4 启动服务
# 先启动 Prometheus 和 Grafana
docker-compose up -d
# 再启动你的应用
python app.py
5.5 验证数据
手动访问一下你的应用,然后看看 /metrics 端点:
curl http://localhost:8000/api/users
curl http://localhost:8000/api/slow
curl http://localhost:8000/metrics
你会看到类似这样的输出:
# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{endpoint="/api/users",method="GET",status="200"} 3.0
http_requests_total{endpoint="/api/slow",method="GET",status="200"} 1.0
http_requests_total{endpoint="/api/slow",method="GET",status="504"} 1.0
# HELP http_request_duration_seconds HTTP request duration in seconds
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{endpoint="/api/users",method="GET",le="0.01"} 0.0
http_request_duration_seconds_bucket{endpoint="/api/users",method="GET",le="0.05"} 3.0
http_request_duration_seconds_bucket{endpoint="/api/users",method="GET",le="0.1"} 3.0
...
5.6 在 Grafana 中查看
打开浏览器访问 http://localhost:3000,用户名 admin,密码 admin123。
第一步:添加数据源。进入 Configuration → Data Sources → Add data source → 选 Prometheus → URL 填 http://prometheus:9090 → Save & Test。
第二步:创建 Dashboard。进入 Dashboards → New Dashboard → Add Panel → 在查询框里输入:
rate(http_requests_total[1m])
这条 PromQL 的意思是:计算过去 1 分钟内请求速率的变化。你会看到一条实时变化的曲线。
六、PromQL:监控世界的查询语言
PromQL 是 Prometheus 的查询语言,类似于 SQL 之于数据库。你不需要精通,但几个最常用的必须会。
6.1 常用函数速查表
| 函数 | 作用 | 示例 |
|---|---|---|
rate() |
计算每秒平均增长率 | rate(http_requests_total[5m]) |
increase() |
计算时间段内的增量 | increase(http_requests_total[1h]) |
histogram_quantile() |
计算分位值 | histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) |
sum() |
求和 | sum(rate(http_requests_total[5m])) by (endpoint) |
avg() |
求平均 | avg(node_cpu_seconds_total) by (instance) |
6.2 实战 PromQL
我列出几个你上线后一定会用到的查询:
# 1. 当前 QPS(每秒请求数)
sum(rate(http_requests_total[1m]))
# 2. 按接口分组的 QPS
sum(rate(http_requests_total[1m])) by (endpoint)
# 3. P99 响应时间
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, endpoint))
# 4. 错误率(5xx 占比)
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
# 5. 在线用户数
online_users
我当初学 PromQL 的时候,最大的坑是 rate() 和 increase() 搞混。记住:rate() 返回的是"每秒"的速率,increase() 返回的是"整个时间段"的增量。如果你要看"过去一小时多了多少请求",用 increase();如果你要看"现在的请求速率是多少",用 rate()。
七、告警:监控的灵魂
监控如果不告警,那就只是一块好看的屏幕。告警才是监控真正发挥价值的地方。
7.1 配置告警规则
在 prometheus.yml 中添加告警规则文件引用:
global:
scrape_interval: 15s
rule_files:
- 'alert_rules.yml'
scrape_configs:
- job_name: 'my-app'
static_configs:
- targets: ['host.docker.internal:8000']
创建 alert_rules.yml:
groups:
- name: my-app-alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: "错误率超过 5%"
description: "当前错误率为 {{ $value | humanizePercentage }}"
- alert: SlowResponse
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
) > 1.0
for: 5m
labels:
severity: warning
annotations:
summary: "P99 响应时间超过 1 秒"
7.2 告警规则解读
每条告警规则有三个关键部分:
expr:触发条件,用 PromQL 写for:持续时间,满足条件多久后才真正告警(防止瞬时抖动误报)labels和annotations:告警的标签和描述信息
这里有一个架构设计上的思考:for 字段非常重要。如果接口偶尔有一个慢请求,P99 可能瞬间飙高,但几秒钟就恢复了。如果不设 for,你会收到一堆无意义的告警,最后把所有告警都屏蔽掉——这就叫"告警疲劳",是监控体系里最危险的事情。
八、日志监控:别忘了另一半
指标监控告诉你"系统慢了",日志监控告诉你"为什么慢"。两者缺一不可。
8.1 日志收集架构
你的应用(写日志到文件)
│
▼
Filebeat / Fluentd(采集日志)
│
▼
Elasticsearch(存储和检索)
│
▼
Kibana(查看和搜索)
这个组合叫 EFK Stack(Elasticsearch + Fluentd/Filebeat + Kibana),是日志监控的事实标准。
8.2 用 Docker 快速搭建 EFK
在 docker-compose.yml 中追加:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.10.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- "9200:9200"
kibana:
image: docker.elastic.co/kibana/kibana:8.10.0
ports:
- "5601:5601"
depends_on:
- elasticsearch
8.3 应用端日志规范
日志不是随便写就行的。好的日志应该包含:
- 时间戳
- 日志级别(INFO / WARN / ERROR)
- 请求 ID(用于链路追踪)
- 关键上下文(用户 ID、接口路径等)
import logging
import uuid
logging.basicConfig(
format='%(asctime)s [%(levelname)s] [request_id=%(request_id)s] %(message)s',
level=logging.INFO
)
class RequestIDFilter(logging.Filter):
def filter(self, record):
record.request_id = getattr(record, 'request_id', str(uuid.uuid4())[:8])
return True
logger = logging.getLogger(__name__)
logger.addFilter(RequestIDFilter())
@app.route('/api/users')
def get_users():
request_id = str(uuid.uuid4())[:8]
logger.info("Handling request", extra={'request_id': request_id})
# ... 业务逻辑
logger.info("Request completed", extra={'request_id': request_id})
return jsonify({"users": ["Alice", "Bob"]})
九、新手常见问题
Q1:Prometheus 数据能存多久?
默认情况下,Prometheus 本地存储保留 15 天。可以通过启动参数 --storage.tsdb.retention.time=30d 改成 30 天。但 Prometheus 不适合做长期存储,长期数据建议用 Thanos 或 VictoriaMetrics。
Q2:我的应用是 Java/Go/Node.js,怎么接入?
每种语言都有对应的 Prometheus Client 库:
| 语言 | 库名 | 安装方式 |
|---|---|---|
| Python | prometheus_client | pip install prometheus_client |
| Java | micrometer | Maven 依赖 |
| Go | prometheus/client_golang | go get github.com/prometheus/client_golang |
| Node.js | prom-client | npm install prom-client |
接入思路完全一样:定义指标 → 在代码中埋点 → 暴露 /metrics 端点。
Q3:指标太多了,Prometheus 扛不住怎么办?
这是架构设计中常见的问题。几个解决思路:
- 减少标签组合:不要把用户 ID 这种高基数字段作为标签
- 用 Recording Rules 预计算:把复杂的 PromQL 提前算好,存成新的指标
- 分片部署:用 Thanos 或 Prometheus Federation 做水平扩展
Q4:Grafana 面板太多,看不过来怎么办?
按照"总—分—细"的层级设计 Dashboard:
- L1 总览面板:一眼看到系统整体健康状态(绿/黄/红)
- L2 模块面板:按服务或模块分组,看各模块的核心指标
- L3 详情面板:排查问题时下钻,看具体接口、具体机器的详细数据
十、学习建议与避坑指南
10.1 我踩过的坑
一开始就想搞全套:Prometheus + Grafana + Alertmanager + Thanos + Loki + Tempo... 新手千万别这么干。先把 Prometheus + Grafana 跑通,能监控一个接口,就已经超过 80% 的团队了。
告警规则写得太敏感:接口超时一次就告警,结果一天收 500 条告警,最后全忽略了。记住:宁可漏报,不可误报。误报多了,人会麻木。
只监控不演练:监控搭好了,但从没验证过告警能不能发出来。建议定期做"混沌工程"演练,主动制造故障,验证监控是否真的能发现。
10.2 下一步学习路径
入门:Prometheus + Grafana 跑通(你现在在这里)
│
▼
进阶:接入 Alertmanager,配置钉钉/企微/邮件告警
│
▼
中级:学习日志监控(EFK Stack)和链路追踪(Jaeger / SkyWalking)
│
▼
高级:学习 Thanos / VictoriaMetrics 做长期存储和高可用
│
▼
专家:设计完整的可观测性体系(Metrics + Logs + Traces 三支柱)
10.3 推荐资源
- Prometheus 官方文档:https://prometheus.io/docs/
- Grafana 官方教程:https://grafana.com/tutorials/
- 《Prometheus 监控实战》这本书,适合系统学习
总结
监控工具的本质,是给系统装上"神经系统"。它由四层组成:数据源、采集层、存储层、展示层。Prometheus 用 Pull 模型主动拉取指标,Grafana 负责可视化,Alertmanager 负责告警。
从架构设计的角度,监控体系有三个核心原则:
- 可观测性优先于可监控性——先让系统"可被观察",再谈"可被监控"
- 告警要少而精——每一条告警都应该是需要人工介入的
- 监控要像代码一样管理——配置文件版本化,Dashboard 代码化
我当初花了半年才把这些概念串起来。希望这篇文章能帮你把这条路缩短到一周。
去跑通你的第一个 Dashboard 吧。当你第一次看到自己写的接口 QPS 曲线在 Grafana 上跳动的时候,你会觉得这一切都值得。

评论 0