Lesson 0009:监控 & 可观测性——看不见的问题就是定时炸弹

DevOps 四大支柱的最后一根:监控(Monitoring)和可观测性(Observability)。前 8 课教你构建和部署,这一课教你知道系统还活着

三个层次:Metrics、Logs、Traces

层次回答什么问题工具
Metrics(指标)「系统整体怎么样?」CPU、内存、请求速率、错误率Prometheus
Logs(日志)「具体发生了什么?」某次请求的详细信息、错误堆栈Loki / ELK
Traces(链路追踪)「一个请求经过了哪些服务?」微服务间的调用链Jaeger / Tempo

这节课聚焦 Metrics——最基础也最重要的监控层。学会 Metrics,你就覆盖了 80% 的日常监控需求。

Prometheus + Grafana:监控的黄金搭档

你的服务器 ──→ Node Exporter(采集系统指标)
你的应用   ──→ 暴露 /metrics 端点
                    ↓ scrape(定期抓取)
              Prometheus(存储 + 查询)
                    ↓ 数据源
               Grafana(可视化仪表盘 + 告警)

动手:10 分钟搭一套监控栈

mkdir /tmp/monitoring && cd /tmp/monitoring

cat > docker-compose.yml << 'EOF'
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prom_data:/prometheus
    ports:
      - "9090:9090"
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    ports:
      - "9100:9100"

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana

volumes:
  prom_data:
  grafana_data:
EOF

cat > prometheus.yml << 'EOF'
global:
  scrape_interval: 15s       # 每 15 秒抓一次

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']    # Docker 内部 DNS
EOF

docker compose up -d

# 验证
curl http://localhost:9090   # Prometheus UI
curl http://localhost:9100/metrics | head -20  # 裸指标数据(看着吓人但不用你读)
curl http://localhost:3000   # Grafana(admin / admin)

PromQL:Prometheus 的查询语言

打开 http://localhost:9090,在 Graph 标签页里试试这些查询:

# CPU 使用率(所有核心平均)
rate(node_cpu_seconds_total{mode="user"}[5m]) * 100

# 内存使用百分比
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

# 磁盘可用空间(GB)
node_filesystem_avail_bytes / 1024 / 1024 / 1024

# 网络接收速率(bytes/sec)
rate(node_network_receive_bytes_total[5m])
PromQL 函数作用
rate(metric[5m])计算 5 分钟内的每秒增长率(最常用)
avg(metric)平均值
sum(metric)求和
{job="node"}按 job 标签过滤
> 80只显示值大于 80 的

Grafana Dashboard:从数据到图表

打开 http://localhost:3000(admin/admin),三步创建仪表盘:

  1. 添加数据源:Connections → Data Sources → Prometheus → URL 填 http://prometheus:9090 → Save & test
  2. 导入现成仪表盘:Dashboards → Import → 输入 1860(Node Exporter Full 模板 ID)→ 选 Prometheus 数据源 → Import
  3. 瞬间看到 CPU、内存、磁盘、网络的完整仪表盘!
Grafana 社区有成千上万个预建仪表盘:grafana.com/grafana/dashboards/。几乎任何东西都有现成的——Node Exporter、Nginx、PostgreSQL、Docker、Kubernetes。导入 ID 就行,不用自己画。

告警:比你先知道出问题了

监控让你能看到问题。告警让问题来找你

# alert.rules.yml(放在 prometheus.yml 同目录,在 prometheus.yml 里引用它)
groups:
  - name: node-alerts
    rules:
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 5m                           # 持续 5 分钟才告警(防止抖动)
        labels:
          severity: warning
        annotations:
          summary: "High CPU usage on {{ $labels.instance }}"
          description: "CPU usage is {{ $value }}% for 5 minutes"

      - alert: DiskAlmostFull
        expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 10
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Disk almost full on {{ $labels.instance }}"
          description: "Only {{ $value }}% space left"

告警可以推到 Slack、钉钉、邮件、PagerDuty。在 Grafana 里也能配告警——但 Prometheus Alertmanager 更专业(去重、分组、静默、升级)。

给你的应用加 Metrics

Node Exporter 监控的是服务器。你自己的应用也需要暴露指标:

// Node.js 示例:用 prom-client 库
const prometheus = require('prom-client');
const http = require('http');

// 创建一个计数器:记录 HTTP 请求总数
const httpRequestsTotal = new prometheus.Counter({
  name: 'http_requests_total',
  help: 'Total number of HTTP requests',
  labelNames: ['method', 'status']
});

// 在你的请求处理里
app.use((req, res, next) => {
  res.on('finish', () => {
    httpRequestsTotal.inc({ method: req.method, status: res.statusCode });
  });
  next();
});

// 暴露 /metrics 端点(Prometheus 来 scrape 这个端点)
app.get('/metrics', async (req, res) => {
  res.set('Content-Type', prometheus.register.contentType);
  res.end(await prometheus.register.metrics());
});

然后在 prometheus.yml 里加一个 scrape target 指向你的应用端口,Prometheus 就开始收集你的业务指标了。

RED 方法(面试常考):对每个服务监控三个核心指标——Rate(每秒请求数)、Errors(错误率)、Duration(响应延迟)。再加一个 USE 方法(系统层)——Utilization、Saturation、Errors。这两个方法论帮你回答「该监控什么」。

小测验

Q1:Prometheus 获取指标数据的方式是什么?
Q2:RED 方法中的 R、E、D 分别代表什么?
Q3:Node Exporter 的作用是什么?
Q4:告警规则里 for: 5m 的含义是什么?

推荐资源

🎉 恭喜!这是 9 节核心课程的最后 1 节。你已经覆盖了 DevOps 的全部基础层:概念 → Linux → Git → 脚本 → Docker → CI/CD → 部署 → IaC → 监控。
← Lesson 0008 · 术语表 · Mission