属于我们的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回答“瓶颈在哪里?”
单个用户对电子商务结帐的请求可能会涉及:
- 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 仪表板
仪表板层次结构
- 概览仪表板:所有服务的高级运行状况。这是发生事件时任何人看到的第一个屏幕。
- 服务仪表板:每个服务(API、Web、工作人员)的详细指标。
- 基础设施仪表板:节点级指标(CPU、内存、磁盘、网络)。
- 业务仪表板:收入、订单、用户活动。
服务仪表板的 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 发布——帮助企业了解生产中的重要因素。
作者
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
相关文章
Webhook 调试和监控:完整的故障排除指南
通过这份涵盖故障模式、调试工具、重试策略、监控仪表板和安全最佳实践的完整指南掌握 Webhook 调试。
GitHub Actions Monorepo 项目的 CI/CD
Turborepo monorepos 的完整 GitHub Actions CI/CD 指南:仅受影响的构建、并行作业、缓存策略、基于环境的部署和安全最佳实践。
在生产中测试和监控 AI 代理
在生产环境中测试和监控 AI 代理的完整指南。涵盖 OpenClaw 部署的评估框架、可观测性、漂移检测和事件响应。
更多来自Performance & Scalability
Webhook 调试和监控:完整的故障排除指南
通过这份涵盖故障模式、调试工具、重试策略、监控仪表板和安全最佳实践的完整指南掌握 Webhook 调试。
k6 负载测试:在发布之前对您的 API 进行压力测试
掌握 Node.js API 的 k6 负载测试。涵盖虚拟用户启动、阈值、场景、HTTP/2、WebSocket 测试、Grafana 仪表板和 CI 集成模式。
Nginx 生产配置:SSL、缓存和安全性
Nginx 生产配置指南:SSL 终止、HTTP/2、缓存标头、安全标头、速率限制、反向代理设置和 Cloudflare 集成模式。
Odoo 性能调优:PostgreSQL 和服务器优化
Odoo 19 性能调优专家指南。涵盖 PostgreSQL 配置、索引、查询优化、Nginx 缓存和企业部署的服务器大小调整。
Odoo 与 Acumatica:适合成长型企业的云 ERP
2026 年 Odoo 与 Acumatica 的比较:独特的定价模型、可扩展性、制造深度以及哪种云 ERP 适合您的增长轨迹。
在生产中测试和监控 AI 代理
在生产环境中测试和监控 AI 代理的完整指南。涵盖 OpenClaw 部署的评估框架、可观测性、漂移检测和事件响应。