轻量级监控方案实战:Grafana Stack 与自托管可观测性的完整搭建
一、可观测性不是「有了监控仪表盘就够了的」,而是「出问题时,你能多快定位到根因」
很多团队在搭建监控系统时,把重点放在了「采集了多少指标」、「仪表盘有多漂亮」上,而没有认真想过「当生产环境出问题时,监控能帮助我多快定位根因」。一个真正有用的监控系统,需要回答三个问题:系统现在健康吗(实时监控)、出问题了哪里出的问题(分布式追踪)、以及为什么出问题(日志分析)。这三个问题对应可观测性的三大支柱:Metrics(指标)、Tracing(追踪)、Logging(日志)。
Grafana Stack(Prometheus + Grafana + Loki + Tempo)是目前最主流的开源可观测性方案。它的核心优势是「全栈开源、社区成熟、可以完全自托管」。Prometheus 做指标采集和存储、Grafana 做指标可视化和告警、Loki 做日志聚合和查询、Tempo 做分布式追踪。这四个组件可以独立使用,也可以组合成完整的可观测性平台。
但 Grafana Stack 的搭建和运维有一定的复杂度。对于小团队或者独立开发者,如果只是为了「看看服务器 CPU 和内存使用情况」,用 CloudWatch、Datadog 或者 Vercel 自带的监控可能更省事。Grafana Stack 适合「需要自定义指标、需要长期存储监控数据、或者对数据主权有要求」的场景。
二、Grafana Stack 架构解析:四大组件的职责与协作方式
flowchart TD A[应用/服务] --> B[Prometheus 抓取指标] A --> C[Loki 收集日志] A --> D[Tempo 接收追踪] B --> E[Grafana 可视化] C --> E D --> E E --> F[告警通知] B --> G[指标存储] C --> H[日志存储] D --> I[追踪存储]Prometheus是 Grafana Stack 的核心。它是一个时序数据库,负责「抓取」或者「接收」指标数据,存储起来,并支持用 PromQL 查询。Prometheus 的抓取模式是「拉模式」:Prometheus 主动去配置的端点抓指标。大部分技术栈都有 Prometheus 的客户端库(如prom-clientfor Node.js、prometheus_clientfor Python),应用在/metrics端点暴露指标,Prometheus 定期来抓。
Grafana是可视化层。它连接 Prometheus(或者其他数据源,如 Loki、Tempo、PostgreSQL),提供查询界面和仪表盘。Grafana 的仪表盘是 JSON 格式的,可以版本管理、可以导入社区分享的仪表盘、也可以根据最佳实践自动生成。
Loki是日志聚合系统,它的设计理念是「像 Prometheus 对待指标一样对待日志」。和 ELK(Elasticsearch + Logstash + Kibana)相比,Loki 不索引日志全文,只索引元数据(如时间戳、服务名、日志级别),所以存储和计算成本更低。Loki 的查询语言 LogQL 也设计得和 PromQL 类似,降低了学习成本。
Tempo是分布式追踪系统,它接收来自应用的追踪数据(通常是 OpenTelemetry 格式),存储起来,并支持在 Grafana 里做端到端追踪可视化。Tempo 的设计目标是「低成本、大规模」,它不索引追踪数据的内容,只索引 Trace ID,所以存储成本比 Jaeger 或者 Zipkin 低。
三、Prometheus + Grafana 快速搭建:Docker Compose 实战
用 Docker Compose 搭建一个最小可用的 Prometheus + Grafana 监控栈,只需要几分钟。以下是一个docker-compose.yml示例:
version: "3" services: prometheus: image: prom/prometheus:latest ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus command: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" grafana: image: grafana/grafana:latest ports: - "3000:3000" volumes: - grafana-data:/var/lib/grafana depends_on: - prometheus volumes: prometheus-data: grafana-data:prometheus.yml是 Prometheus 的配置文件,定义抓取目标和抓取间隔:
global: scrape_interval: 15s scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"] - job_name: "my-app" static_configs: - targets: ["my-app:3000"] # 应用的 /metrics 端点在应用里添加/metrics端点(以 Node.js + Express 为例):
import express from "express"; import client from "prom-client"; const app = express(); const register = client.register; // 自动采集默认指标(Node.js 运行时指标) client.collectDefaultMetrics(); app.get("/metrics", async (req, res) => { res.set("Content-Type", register.contentType); res.end(await register.metrics()); }); app.listen(3000);启动 Docker Compose 后,访问http://localhost:3000(Grafana,默认账号 admin/admin),添加 Prometheus 作为数据源(http://prometheus:9090),然后导入社区仪表盘(如 Node.js 的仪表盘 ID11969),就能看到应用的运行时指标了。
四、告警配置与生产监控的关键细节
监控系统的最终价值,在于「出问题的时候有人知道」。Grafana 的告警系统支持多种通知渠道:邮件、Slack、PagerDuty、Webhook(可以接入任何系统)。配置告警的核心原则是「减少告警疲劳」——只有当问题确实需要人工处理时,才发告警。
以下是一个 Prometheus 告警规则的示例(在prometheus.yml里配置,或者用单独的alerts.yml):
groups: - name: app-alerts rules: - alert: HighErrorRate expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05 for: 2m labels: severity: critical annotations: summary: "错误率超过 5%" description: "服务 {{ $labels.instance }} 的 5xx 错误率超过 5%,持续 2 分钟" - alert: HighResponseTime expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1 for: 5m labels: severity: warning annotations: summary: "P95 响应时间超过 1 秒"这个配置里有两个关键设计:「for: 2m」表示条件持续 2 分钟后才触发告警,避免瞬时的波动导致误报;「severity标签」用来区分告警的严重等级,可以在通知时做不同处理(如 critical 发短信,warning 只发 Slack)。
生产监控还需要关注「监控系统的健康状态」。如果 Prometheus 或者 Grafana 挂了,监控就失效了。对于自托管的监控栈,建议用外部监控服务(如 UptimeRobot、Pingdom)监控 Grafana 的可用性,或者用另一个小型监控系统监控主监控系统。
五、总结
Grafana Stack 提供了一套完整的、开源的、可自托管的可观测性方案。Prometheus 采集和存储指标、Grafana 提供可视化和告警、Loki 做日志聚合、Tempo 做分布式追踪。对于需要自定义监控、长期存储监控数据或者对数据主权有要求的团队,Grafana Stack 是最成熟的开源选择。但搭建和维护这套系统需要投入时间,对于小团队或者早期项目,先用托管监控服务(如 Vercel Analytics、Sentry Performance)可能是更务实的选择。可观测性的目标不是「采集所有数据」,而是「出问题时能快速定位根因」——围绕这个目标选择工具和投资,才不会在监控上过度工程化。