这次我们来看一个很多团队容易混淆的概念:可观测性与 Monitor(监控)。两者经常被放在同一个文件目录下,但解决的问题完全不同。监控是“我知道它挂了”,可观测性是“我知道它为什么挂”。如果你正在搭告警体系、做日志采集、排查链路瓶颈,或者刚从“只看 CPU 和内存”的阶段往“全链路可观测”的方向升级,这篇文章可以直接收藏。
我们先说结论:可观测性不是采购一个大屏监控工具就算完成,它由 Logs(日志)、Metrics(指标)、Traces(链路)三部分组成,习惯上称为“三大支柱”。而 Monitor 通常指持续采集、聚合、展示指标并触发告警的系统,比如 Prometheus、Grafana、Zabbix。这篇文章会基于一套主流开源实践,演示如何在本地环境部署 Prometheus + Grafana + Loki + OpenTelemetry,完成从指标监控、日志采集到链路追踪的一整套可观测性平台搭建,并把常见问题和性能观察方法一并梳理清楚。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 可观测性平台搭建实践,覆盖 Metrics、Logs、Traces 三大支柱 |
| 核心组件 | Prometheus、Grafana、Loki、Promtail、OpenTelemetry Collector、Alertmanager |
| 主要功能 | 指标采集与告警、日志聚合检索、分布式链路追踪、可视化大屏 |
| 推荐硬件 | 8GB 内存以上,2 核 CPU 以上,磁盘预留 50GB(按日志量评估) |
| 数据存储 | Prometheus TSDB、Loki 日志存储,默认本地磁盘,可接对象存储 |
| 支持平台 | Linux / Windows / macOS,推荐 Linux 服务器长期运行 |
| 启动方式 | Docker Compose 一键拉起,或二进制 / systemd 分别部署 |
| 是否支持 API | 支持。Prometheus / Alertmanager / Loki / Grafana 均提供 HTTP API |
| 是否支持批量任务 | 支持批量采集、批量告警规则加载、多实例抓取 |
| 适合场景 | 微服务监控、容器平台观测、传统 IDC 基础设施监控、日志排查与链路诊断 |
从材料看,这类方案适合已经有基础服务、但监控能力分散在多个平台的团队,也适合刚开始建设统一可观测性的个人开发者。
2. 适用场景与使用边界
可观测性平台不是越大越好,先明确它适合什么、不适合什么。
2.1 适合什么
- 现有服务只有零散日志,缺少统一检索入口,排查问题靠翻文件。
- 已经用 Kubernetes 或其他容器平台,需要监控 Pod、Node、应用指标。
- 微服务调用链路过长,接口变慢时无法快速定位是哪个环节导致的。
- 需要把告警发到钉钉、企业微信、邮件,并且对告警做去重和静默管理。
2.2 不适合什么
- 业务规模很小、只有一台服务器且不需要长期留存日志,直接用云厂商自带监控更省事。
- 需要 APM 级别的代码级性能分析,单靠 Prometheus 指标不够,要结合 SkyWalking 或商业 APM 工具。
- 团队没有精力维护中间件,更建议使用托管的云可观测服务。
- 日志量为 PB 级且需要复杂分析,Loki 会显得吃力,这类场景一般要引入专门的日志分析平台。
2.3 合规与安全边界
部署可观测性平台会采集大量日志和指标,其中可能包含用户 IP、请求路径、错误堆栈等敏感信息。建议:
- 日志采集前做脱敏处理,避免记录完整 Cookie、Token、身份证号等字段。
- 监控平台本身要启用认证,Grafana 至少设置强密码或接入统一身份认证。
- 链路追踪数据中避免透传业务敏感字段。
- 对外提供监控面板或 API 时,只暴露必要数据,并确认已获得业务方授权。
3. 环境准备与前置条件
建议使用 Linux 服务器部署,版本不限,关键是 Docker 环境可用。这里给出一套通用检查清单。
3.1 硬件与系统要求
- CPU:2 核以上,多任务采集建议 4 核。
- 内存:8GB 起步。Prometheus、Loki、Grafana 同时运行,叠加采集任务,4GB 会比较紧张。
- 磁盘:SSD 更稳。Prometheus 默认保留 15 天数据,Loki 按日志量增长,建议预留 50GB 以上。
- 系统:CentOS 7+、Ubuntu 20.04+、Debian 11+ 均可,Windows 也能跑但生产环境不推荐。
3.2 软件依赖清单
| 组件 | 版本建议 | 说明 |
|---|---|---|
| Docker | 20.10+ | 容器运行基础 |
| Docker Compose | v2 以上 | 一键编排服务 |
| Prometheus | 2.47+ | 指标采集与存储 |
| Grafana | 10.x | 可视化查询与告警展示 |
| Loki | 2.9.x | 日志存储与查询 |
| Promtail | 2.9.x | 日志采集 Agent |
| OpenTelemetry Collector | 0.88+ | 链路与指标转发 |
如果不用 Docker,也可以直接下载各组件二进制包,但依赖管理更繁琐。个人建议先用 Docker Compose 建一套最小可用环境。
3.3 端口规划
默认端口如下:
| 服务 | 端口 | 用途 |
|---|---|---|
| Prometheus | 9090 | Web UI 与 API |
| Grafana | 3000 | 可视化控制台 |
| Loki | 3100 | 日志写入与查询 API |
| Alertmanager | 9093 | 告警统一管理 |
| OpenTelemetry Collector | 4317 / 4318 | OTLP gRPC / HTTP 接收 |
实际部署时,如果端口冲突,用环境变量或 docker-compose 里的 ports 映射修改即可。
4. 一键部署与启动方式
下面用 Docker Compose 搭建一套基础可观测性平台。这里采用通用配置模板,实际使用时要按你的服务目录和日志路径调整。
4.1 创建项目目录
mkdir -p ~/observability/{prometheus,grafana,loki,promtail,otel-collector} cd ~/observability4.2 编写 docker-compose.yml
version: "3.8" services: prometheus: image: prom/prometheus:latest container_name: prometheus restart: unless-stopped ports: - "9090:9090" volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus command: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.retention.time=15d" grafana: image: grafana/grafana:latest container_name: grafana restart: unless-stopped ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_USER=admin - GF_SECURITY_ADMIN_PASSWORD=admin123 volumes: - grafana-data:/var/lib/grafana loki: image: grafana/loki:latest container_name: loki restart: unless-stopped ports: - "3100:3100" volumes: - ./loki/loki-config.yaml:/etc/loki/loki-config.yaml - loki-data:/loki command: - "-config.file=/etc/loki/loki-config.yaml" promtail: image: grafana/promtail:latest container_name: promtail restart: unless-stopped volumes: - ./promtail/promtail-config.yaml:/etc/promtail/promtail-config.yaml - /var/log:/var/log:ro command: - "-config.file=/etc/promtail/promtail-config.yaml" otel-collector: image: otel/opentelemetry-collector-contrib:latest container_name: otel-collector restart: unless-stopped ports: - "4317:4317" - "4318:4318" volumes: - ./otel-collector/otel-config.yaml:/etc/otel-collector-config.yaml command: - "--config=/etc/otel-collector-config.yaml" alertmanager: image: prom/alertmanager:latest container_name: alertmanager restart: unless-stopped ports: - "9093:9093" volumes: - ./prometheus/alertmanager.yml:/etc/alertmanager/alertmanager.yml command: - "--config.file=/etc/alertmanager/alertmanager.yml" volumes: prometheus-data: grafana-data: loki-data:这里把核心组件都编排到一个栈里。实际工作中,如果你只想先验证指标监控,可以只启动 Prometheus 和 Grafana,其他组件按需追加,减少资源占用。
4.3 编写 Prometheus 配置
global: scrape_interval: 15s evaluation_interval: 15s rule_files: - "/etc/prometheus/rules.yml" alerting: alertmanagers: - static_configs: - targets: ["alertmanager:9093"] scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"] - job_name: "node-exporter" static_configs: - targets: ["node-exporter:9100"]如果暂时没有 node-exporter,可以先把 node-exporter 的任务注释掉,避免启动后一直报抓取错误。
4.4 编写 Loki 配置
auth_enabled: false server: http_listen_port: 3100 common: path_prefix: /loki storage: filesystem: chunks_directory: /loki/chunks rules_directory: /loki/rules replication_factor: 1 ring: kvstore: store: inmemory schema_config: configs: - from: 2024-01-01 store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h limits_config: retention_period: 168h ruler: alertmanager_url: http://alertmanager:9093这里配置了 7 天日志保留时间。如果磁盘紧张,可以改为 24h 或 72h。
4.5 启动服务
docker compose up -d启动后检查服务状态:
docker compose ps正常情况下可以看到所有容器处于 Up 状态。访问以下地址验证基础服务:
- Prometheus 控制台:
http://服务器IP:9090 - Grafana 登录页:
http://服务器IP:3000 - Alertmanager 界面:
http://服务器IP:9093 - Loki 健康检查:
http://服务器IP:3100/ready
到这里,一套最小可运行的可观测性基础设施就起来了。
5. 功能测试与效果验证
部署完成不等于可用。下面按“指标 -> 日志 -> 链路”的顺序走一遍验证流程。
5.1 指标监控验证
Prometheus 自身会暴露prometheus_http_requests_total等指标。
在 Prometheus 控制台执行查询:
rate(prometheus_http_requests_total[5m])如果返回非空数据,说明采集链路正常。接着在 Grafana 中添加 Prometheus 数据源:
- URL 填写
http://prometheus:9090 - 请求头不需要额外配置
添加完成后新建一个 Dashboard,选择prometheus_http_requests_total指标,即可看到请求量曲线。
这一步验证的是整个指标链路是否通畅:抓取 -> 存储 -> 查询 -> 可视化。
5.2 日志采集验证
如果 Promtail 配置正确,Loki 中就能搜到本机/var/log下相关日志。在 Grafana 的 Explore 页面,数据源选择 Loki,在查询框中输入:
{job="varlogs"}如果返回日志流,说明日志链路正常。
Loki 的查询语法也是生产环境排查问题的重要手段,比如按关键词过滤:
{job="varlogs"} |= "error"这条查询会返回包含error的日志行,定位问题时非常实用。
5.3 链路追踪验证
链路追踪需要业务服务配合注入 OpenTelemetry SDK。这里先验证 OpenTelemetry Collector 是否正常接收数据。
启动后,向 Collector 发送 OTLP HTTP 请求:
curl -X POST http://127.0.0.1:4318/v1/traces \ -H "Content-Type: application/json" \ -d '{"resourceSpans":[]}'返回200说明 Collector 已正常接收 Trace 数据。实际业务接入时,在服务中将 OTLP Endpoint 指向http://collector地址:4317或4318即可。
5.4 告警功能验证
告警规则的验证分为两步。
第一步,准备一个测试告警规则文件prometheus/rules.yml:
groups: - name: instance_down rules: - alert: InstanceDown expr: up == 0 for: 1m labels: severity: critical annotations: summary: "Instance {{ $labels.instance }} down"第二步,重启 Prometheus 或热加载配置:
docker exec prometheus kill -HUP 1在 Prometheus 的 Alerts 页面,如果能看到InstanceDown规则并且状态为firing,说明告警规则生效。
6. 接口 API 与批量任务
可观测性平台的核心价值之一是开放 API,方便接入自己的自动化体系。
6.1 Prometheus HTTP API
查询指标数据:
curl -G http://127.0.0.1:9090/api/v1/query \ --data-urlencode 'query=up'返回格式为 JSON,包含status和data。这是最常用的 API,适合做自动化巡检和报告生成。
6.2 Alertmanager API
查看当前告警:
curl http://127.0.0.1:9093/api/v2/alerts批量静默一个告警:
curl -X POST http://127.0.0.1:9093/api/v2/silences \ -H "Content-Type: application/json" \ -d '{ "matchers": [ {"name": "alertname", "value": "InstanceDown", "isRegex": false} ], "startsAt": "2024-01-01T00:00:00Z", "endsAt": "2024-01-02T00:00:00Z", "createdBy": "automation", "comment": "scheduled maintenance" }'批量静默是发布窗口期最常用的能力,避免维护期间产生大量误报。
6.3 Loki API
按查询语句拉取日志:
curl -G http://127.0.0.1:3100/loki/api/v1/query_range \ --data-urlencode 'query={job="varlogs"}' \ --data-urlencode 'start=2024-01-01T00:00:00Z' \ --data-urlencode 'end=2024-01-02T00:00:00Z'Python 脚本批量拉取多个服务的日志并生成报告,也是常见用法:
import requests import time loki_url = "http://127.0.0.1:3100" def query_logs(query, start_ns, end_ns): params = { "query": query, "start": start_ns, "end": end_ns } resp = requests.get(f"{loki_url}/loki/api/v1/query_range", params=params) return resp.json() # 查询最近 10 分钟的 varlogs 日志 end_ns = int(time.time()) * 1_000_000_000 start_ns = end_ns - 600 * 1_000_000_000 result = query_logs('{job="varlogs"}', start_ns, end_ns) print(result["data"]["result"])这些 API 通常都有对应的 HTTP 客户端 SDK,接入后可以轻松完成批量拉取、批量告警操作、自动生成巡检报告等工作。
6.4 批量抓取与任务设计
Prometheus 的抓取本身就是批量任务,按job_name分组。实际使用中常见设计是:
- 每类服务建一个 job,用
target列表批量抓取多个实例。 - 采集频率按业务重要性区分,核心服务 15s,非核心服务 30s 或 60s。
- 告警规则按集群、环境、团队标签分组,便于批量管理和路由。
7. 资源占用与性能观察
部署可观测性平台本身也需要被监控,这里讲几个关键点。
7.1 内存与存储观察
Docker 部署下查看容器资源占用:
docker stats不同组件的资源特点不同:
- Prometheus 内存随序列数量和采样频率增长,采集的 target 越多,内存占用越高。
- Loki 磁盘占用与日志写入量直接相关,日志标签设计不合理会导致索引膨胀。
- Grafana 本身轻量,内存占用波动不大。
7.2 降低资源占用的方法
如果服务器配置不高,优先做三件事:
- 降低抓取频率:将
scrape_interval从 15s 调整到 30s 或 60s。 - 减少序列数量:Prometheus 的存储压力主要来自唯一序列数量,标签值越多,序列越多。
- 缩短日志保留时间:Loki 的
retention_period默认 168h,如果日志量大,可以先保留 24h 或 72h。
7.3 日志量与标签设计对性能的影响
这是最容易踩的坑。
Loki 不会对日志内容做全文索引,而是通过标签过滤日志流。如果给每条日志都打上动态标签,比如 request_id 或用户 id,会导致每个请求都产生独立的日志流,索引数量暴涨,查询性能急剧下降。
正确的做法是:静态标签用于分组,比如app、env、host;动态字段保留在日志行内容里,用 LogQL 的解析表达式过滤。
7.4 避免端口冲突与进程残留
多次重启 docker compose 后,偶尔会遇到端口被占用的问题。排查方式:
ss -lntp | grep 9090找到占用进程后,对应停止或换端口。docker compose down 之后,建议用docker compose ps确认容器真正退出。
8. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 服务启动后立即退出 | 配置格式错误或端口冲突 | docker compose logs 服务名查看日志 | 修正 YAML 缩进,换端口 |
| Grafana 无法连接 Prometheus | 网络未连通或数据源地址错误 | 在 Grafana 容器内测试curl prometheus:9090 | 数据源使用容器网络地址,不用 localhost |
Prometheus 页面up == 0 | 目标服务未启动或抓取路径错误 | 在 Targets 页面查看错误信息 | 确认 target 地址能访问,URL 路径正确 |
| Loki 查询无数据 | Promtail 未采集到日志或标签写法错误 | 检查 Promtail 日志,确认日志路径存在 | 调大 Promtail 抓取范围,确认主机日志目录已挂载 |
| 告警不触发 | 规则文件未加载或阈值不对 | 查看 Prometheus Alerts 页面和规则状态 | 热加载配置,检查表达式语法 |
| OTLP Collector 收不到 Trace | 业务 SDK 未配置或端口不通 | journalctl -u otel-collector或容器日志 | 确认 SDK 指向 4317/4318 端口 |
| 内存占用持续上涨 | 抓取目标过多或保留时间过长 | docker stats观察对应容器 | 降低采集频率,缩短保留时间 |
这里最常见的就是“服务间地址写错”问题。容器部署环境下,服务之间要用容器名访问,localhost只代表某个容器内部。
9. 最佳实践与使用建议
9.1 先小规模跑通,再横向扩展
不要第一天就把所有服务、所有日志全量接入。先接 1 到 2 个服务,走通指标、日志、链路三条链路,确认存储增长和查询体验可接受,再逐步扩容。
9.2 目录与配置统一管理
把 Prometheus、Loki、Promtail 等配置文件纳入 Git 管理,每一次变更都记录在案。生产环境建议用命名规范区分不同集群:
job_name: "prod-api" job_name: "prod-worker" job_name: "staging-api"9.3 告警规则设置分级
建议至少分三级:
- 紧急告警:核心服务不可用,需要立即处理。
- 警告告警:资源利用率高或错误率上升,需要关注。
- 信息告警:用于自动化和记录,不直接打扰人。
告警不是越多越好,规则太多只会导致全员告警疲劳。
9.4 日志脱敏与隐私保护
用户请求日志、错误堆栈中可能包含敏感信息。建议在 Promtail 或应用侧做脱敏,规则可以写到日志输出端,避免 Token、密码等字段进入日志系统。
9.5 接口服务访问控制
Grafana、Prometheus API 不建议直接暴露公网。需要使用时有几个选择:
- 反向代理增加认证。
- 通过 Tailscale 等内网方案访问。
- 只开放 API 端口给内网监控网段。
10. 总结与下一步
可观测性与 Monitor 是两件不同的事,但需要一起建设。Monitor 告诉你服务状态,Logger 记录发生了什么,Trace 还原整个调用过程,三者结合才是真正可用的可观测性平台。
这篇文章里留下的最小可用演示栈是 Prometheus + Grafana + Loki + OpenTelemetry Collector + Alertmanager。值得最先验证的功能是:Prometheus 指标是否能正常抓取、Grafana 是否能画出第一张曲线、Loki 是否能搜到第一条日志。这三个场景跑通后,平台的地基就稳了。
最容易踩的坑集中在三处:容器间地址写错、日志标签设计不合理导致索引膨胀、告警规则一次加太多导致告警风暴。
后续可以继续扩展的方向包括:
- 接入 Alertmanager 的企业微信、钉钉、飞书告警通道。
- 将 OpenTelemetry SDK 集成到实际业务服务中,打通 Trace 到 Metrics 的关联。
- 部署 node-exporter 和 cAdvisor,纳入服务器与容器的基础监控。
- 将 Loki 存储切换到对象存储,延长日志保留周期。
建议把这套环境保存成可复用的 Compose 模板,后续新服务接入时直接复制配置、替换抓取目标和标签即可。监控平台不是装完就完,它是一个需要持续调整数据采集、保留策略和告警规则的基础设施。