生产监控和警报:完整的设置指南

使用 Prometheus、Grafana 和 Sentry 设置生产监控和警报。涵盖指标、日志、跟踪、警报策略和事件响应工作流程。

E
ECOSIRE Research and Development Team
|2026年3月16日4 分钟阅读753 字数|

属于我们的Performance & Scalability系列

阅读完整指南

生产监控和警报:完整的设置指南

生产事故平均每分钟停机成本为 5,600 美元。 拥有成熟监控的公司可在 5 分钟内检测到问题,而那些没有监控的公司平均需要 197 分钟才能检测到——这就是小问题和客户流失灾难之间的区别。

本指南涵盖端到端生产监控设置:测量什么、如何收集、在何处可视化以及何时发出警报。

要点

  • 可观察性的三大支柱(指标、日志、跟踪)服务于不同的目的,而这三者都是必要的
  • 对症状(错误率、延迟)而非原因(CPU 使用率)发出警报,将噪音降低 80%
  • 每个警报附带的操作手册可确保一致的事件响应,无论谁在值班
  • 从 5 个基本警报开始,仅在您了解基线后才进行扩展

可观察性的三大支柱

指标

随着时间的推移采样的数值测量值。指标回答“现在发生了什么?”

应用指标

  • 请求率(每秒请求数)
  • 错误率(每秒 5xx 响应)
  • 延迟分布(P50、P95、P99)
  • 活动会话/并发用户

基础设施指标

  • 每个服务的CPU利用率
  • 内存使用和垃圾收集
  • 磁盘 I/O 和可用空间
  • 网络吞吐量

业务指标

  • 每分钟订单数
  • 购物车放弃率
  • 每小时收入
  • 通过端点进行API调用

日志

离散事件的带时间戳的结构化记录。日志回答“为什么会发生?”

{
  "timestamp": "2026-03-16T14:32:01.234Z",
  "level": "error",
  "service": "api",
  "requestId": "req_abc123",
  "userId": "usr_456",
  "message": "Payment processing failed",
  "error": "Stripe API timeout after 30000ms",
  "endpoint": "POST /billing/checkout",
  "duration": 30142
}

记录最佳实践

  • 使用结构化 JSON 日志记录,而不是纯文本
  • 包括跨服务的关联 ID (requestId)
  • 以适当的级别记录(错误表示失败,警告表示降级,信息表示关键事件)
  • 切勿记录敏感数据(密码、令牌、完整信用卡号)

痕迹

通过分布式系统的端到端请求路径。 Traces回答“瓶颈在哪里?”

单个用户对电子商务结帐的请求可能会涉及:

  1. Nginx (2ms) 到 Next.js 前端 (50ms) 到 NestJS API (120ms) 到 PostgreSQL (45ms) 到 Stripe API (800ms) 到电子邮件服务 (200ms)

如果没有跟踪,您会看到“结账需要 1.2 秒”。通过跟踪,您会看到“Stripe API 占结帐延迟的 67%”。


监控堆栈设置

Prometheus + Grafana(自托管)

# docker-compose.monitoring.yml
services:
  prometheus:
    image: prom/prometheus:v2.50.0
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    ports:
      - "9090:9090"
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'
      - '--web.enable-lifecycle'

  grafana:
    image: grafana/grafana:10.3.0
    volumes:
      - grafana-data:/var/lib/grafana
    ports:
      - "3030:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
      - GF_USERS_ALLOW_SIGN_UP=false

  loki:
    image: grafana/loki:2.9.0
    volumes:
      - loki-data:/loki
    ports:
      - "3100:3100"

  alertmanager:
    image: prom/alertmanager:v0.27.0
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
    ports:
      - "9093:9093"

volumes:
  prometheus-data:
  grafana-data:
  loki-data:

普罗米修斯配置

# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "alerts/*.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

scrape_configs:
  - job_name: "api"
    metrics_path: /metrics
    static_configs:
      - targets: ["api:3001"]

  - job_name: "node-exporter"
    static_configs:
      - targets: ["node-exporter:9100"]

  - job_name: "postgres"
    static_configs:
      - targets: ["postgres-exporter:9187"]

  - job_name: "redis"
    static_configs:
      - targets: ["redis-exporter:9121"]

NestJS 应用指标

暴露 Prometheus 指标

// metrics.module.ts
import { Module } from '@nestjs/common';
import { PrometheusModule } from '@willsoto/nestjs-prometheus';
import {
  makeCounterProvider,
  makeHistogramProvider,
  makeGaugeProvider,
} from '@willsoto/nestjs-prometheus';

@Module({
  imports: [
    PrometheusModule.register({
      path: '/metrics',
      defaultMetrics: { enabled: true },
    }),
  ],
  providers: [
    makeCounterProvider({
      name: 'http_requests_total',
      help: 'Total HTTP requests',
      labelNames: ['method', 'path', 'status'],
    }),
    makeHistogramProvider({
      name: 'http_request_duration_seconds',
      help: 'HTTP request duration in seconds',
      labelNames: ['method', 'path'],
      buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
    }),
    makeGaugeProvider({
      name: 'active_connections',
      help: 'Number of active connections',
    }),
  ],
  exports: [PrometheusModule],
})
export class MetricsModule {}

警报配置

五个基本警报

每个生产系统从第一天起就需要这些警报:

# alerts/essential.yml
groups:
  - name: essential
    rules:
      - alert: ServiceDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Service {{ $labels.job }} is down"
          runbook: "https://wiki.example.com/runbooks/service-down"

      - alert: HighErrorRate
        expr: |
          rate(http_requests_total{status=~"5.."}[5m])
          / rate(http_requests_total[5m]) > 0.01
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Error rate above 1% for 5 minutes"
          runbook: "https://wiki.example.com/runbooks/high-error-rate"

      - alert: HighLatency
        expr: |
          histogram_quantile(0.95,
            rate(http_request_duration_seconds_bucket[5m])
          ) > 2
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "P95 latency above 2 seconds"

      - alert: DiskSpaceLow
        expr: |
          node_filesystem_avail_bytes{mountpoint="/"}
          / node_filesystem_size_bytes{mountpoint="/"} < 0.2
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Disk space below 20% on {{ $labels.instance }}"

      - alert: SSLCertExpiringSoon
        expr: |
          probe_ssl_earliest_cert_expiry - time() < 14 * 24 * 3600
        labels:
          severity: warning
        annotations:
          summary: "SSL certificate expires within 14 days"

警报路由

# alertmanager.yml
global:
  slack_api_url: "${SLACK_WEBHOOK_URL}"

route:
  group_by: ['alertname', 'severity']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'default'
  routes:
    - match:
        severity: critical
      receiver: 'pagerduty'
      repeat_interval: 15m
    - match:
        severity: warning
      receiver: 'slack'

receivers:
  - name: 'default'
    slack_configs:
      - channel: '#alerts'
        title: '{{ .GroupLabels.alertname }}'
        text: '{{ .CommonAnnotations.summary }}'

  - name: 'pagerduty'
    pagerduty_configs:
      - routing_key: "${PAGERDUTY_KEY}"
        severity: '{{ .GroupLabels.severity }}'

  - name: 'slack'
    slack_configs:
      - channel: '#alerts-warnings'
        title: '{{ .GroupLabels.alertname }}'

警报质量规则

实践为什么
警惕症状,而非原因“错误率高”是可操作的; “CPU 达到 80%”可能不是
每个警报都有一个操作手册值班工程师不需要在凌晨 3 点思考
警报必须具有可操作性如果没有人能够采取行动,那就是噪音,而不是警报
两周后调整阈值初始阈值是猜测;根据基线进行调整
每月检查警报疲劳如果每天触发警报但没有采取任何行动,请提高阈值或将其删除

Grafana 仪表板

仪表板层次结构

  1. 概览仪表板:所有服务的高级运行状况。这是发生事件时任何人看到的第一个屏幕。
  2. 服务仪表板:每个服务(API、Web、工作人员)的详细指标。
  3. 基础设施仪表板:节点级指标(CPU、内存、磁盘、网络)。
  4. 业务仪表板:收入、订单、用户活动。

服务仪表板的 RED 方法

对于每项服务,显示:

  • Rate:每秒请求数
  • Eerrors:错误率百分比
  • Duration:延迟分布(P50、P95、P99)

这提供了对服务运行状况的即时可见性,而无需认知过载。


使用 Sentry 进行错误跟踪

// sentry.config.ts
import * as Sentry from '@sentry/nestjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
  tracesSampleRate: 0.1,
  profilesSampleRate: 0.1,
  integrations: [
    Sentry.postgresIntegration(),
  ],
  beforeSend(event) {
    // Strip sensitive data
    if (event.request?.headers) {
      delete event.request.headers['authorization'];
      delete event.request.headers['cookie'];
    }
    return event;
  },
});

哨兵提供:

  • 自动错误分组和重复数据删除
  • 带有源映射的堆栈跟踪
  • 发布跟踪(哪个部署引入了错误)
  • 性能监控(交易痕迹)

常见问题

监控堆栈的成本是多少?

自托管(Prometheus + Grafana + Loki):托管资源约为每月 50-100 美元。托管替代方案:Datadog 基础设施起价为 15 美元/主机/月,日志费用为 0.10 美元/GB。 Sentry Cloud 团队计划的价格为 26 美元/月。小型企业合理的起始预算总计为 100-200 美元/月。

What is the difference between monitoring and observability?

监控会在出现问题时告诉您。可观察性告诉你原因。监控是针对已知故障模式的预定义仪表板和警报。可观察性是指使用指标、日志和跟踪来询问有关系统行为的任意问题的能力。两者都需要,但监控是基础。

我们如何避免警觉疲劳?

三个规则:(1) 每个警报都必须需要人工操作,(2) 根据实际基线而不是理论理想设置阈值,(3) 每月检查和调整警报。如果警报每周触发一次以上且无需采取措施,请解决根本问题或提高阈值。遭受警报疲劳的团队会忽略所有警报,包括关键警报。

我们应该以不同的方式监控我们的 ERP 系统吗?

ERP 系统具有独特的监控要求。除了标准 Web 指标之外,还可以监控:数据库连接池使用情况、后台作业队列深度、集成同步状态(Shopify、支付网关)、计划的报告执行时间以及按模块的用户会话计数。 ECOSIRE 提供托管 Odoo 监控 作为我们支持包的一部分。


接下来会发生什么

监控是生产基础设施的眼睛和耳朵。将其与 CI/CD 自动化 配对以提高部署信心,并与 灾难恢复规划 配对以提高弹性。有关全面的 DevOps 路线图,请参阅我们的小型企业 DevOps 指南

联系 ECOSIRE 以监控设置和托管基础设施服务。


由 ECOSIRE 发布——帮助企业了解生产中的重要因素。

E

作者

ECOSIRE Research and Development Team

在 ECOSIRE 构建企业级数字产品。分享关于 Odoo 集成、电商自动化和 AI 驱动商业解决方案的洞见。

通过 WhatsApp 聊天