监控告警:系统的"健康体检"
这是基础设施系列的第5篇文章。前面我们聊了网关、配置中心、消息队列,今天来聊聊一个同样重要但常被忽视的话题——监控告警。
一、为什么监控如此重要?
你有没有遇到过这样的情况:
- 用户反馈系统很慢,但你完全不知道哪里出了问题
- 服务器突然宕机,等用户投诉了才发现
- 明明感觉系统有问题,但打开监控面板,全是空白
这就是缺乏监控的后果。没有监控的系统,就像盲人开车——你永远不知道下一秒会发生什么。
监控的本质是什么?
很多人把监控理解为"看数据",但这个理解太浅了。
监控的本质是:让你的系统变得可观测。
可观测性(Observability)这个词来源于控制理论。一个系统被称为"可观测的",是指通过系统的外部输出(指标、日志、追踪),能够推断出系统内部的状态。就像医生通过体温、血压、心电图这些外部指标,能判断你身体内部哪里出了问题。
一个可观测的系统,应该能回答这三个问题:
- 现在发生什么?(实时状态)—— Metrics
- 为什么发生?(根因分析)—— Logs + Traces
- 将来会发生什么?(趋势预测)—— 历史数据分析
没有监控,这些问题都回答不了。有了监控,你才能真正掌控系统。
可观测性三支柱
业界把可观测性总结为三个支柱,它们各有分工:
- 数值型数据,如 CPU 使用率 75%、请求延迟 50ms
- 适合做告警和趋势分析
- 存储成本低,可长期保留
- 工具:Prometheus、InfluxDB、Datadog
- 文本型数据,记录离散事件
- 适合调试和审计
- 存储成本高,需要采样或分级保留
- 工具:ELK Stack、Loki、Splunk
- 记录请求在分布式系统中的完整路径
- 适合定位分布式系统中的性能瓶颈
- 需要应用配合,侵入性较强
- 工具:Jaeger、Zipkin、SkyWalking
这三个支柱不是互相替代,而是互相补充。就像医学检查:指标是体检报告,日志是病历记录,追踪是 CT 扫描。三者结合,才能全面了解系统健康状况。
三支柱的协同工作
让我们用一个实际场景来说明三支柱如何协同工作:
监控发现:订单服务 P99 延迟从 50ms 飙升到 3s
时间点:14:30-14:45 之间
影响范围:约 5% 的请求受影响
链路追踪显示:慢请求都卡在「查询库存」这一步
调用链路:订单服务 → 库存服务 → MySQL
瓶颈点:库存服务的 MySQL 查询
日志搜索结果:
[14:32:15] ERROR - Slow query detected: SELECT * FROM inventory WHERE sku_id = 'SKU001'
[14:32:15] WARN - Query took 2847ms, rows scanned: 500000
根因:某个 SKU 的库存查询触发了全表扫描
这就是三支柱的威力:Metrics 告诉你"有问题",Traces 告诉你"问题在哪",Logs 告诉你"为什么"。
监控带来的价值
根据 Google SRE 的数据,完善的监控可以把平均故障发现时间(MTTD)从 30 分钟缩短到 5 分钟以内。这意味着用户受影响的时间减少了 80% 以上。
一个形象的比喻:没有监控就像医生没有听诊器和化验报告,只能靠"望闻问切"来诊断病情。有了监控,就等于有了 CT、核磁共振、血液分析,问题一目了然。
举个例子:通过监控发现某个接口的 P99 延迟是 P50 的 10 倍,深入分析后发现是某个慢查询拖累了整体性能。优化这个查询后,P99 延迟下降了 80%,用户体验大幅提升。
某电商公司通过分析监控数据,发现晚上 10 点是下单高峰,于是把大促活动的时间调整到这个时段,结果转化率提升了 15%。
二、监控指标设计
知道了监控的重要性,接下来一个问题:到底该监控什么?
很多人犯的错误是:什么都监控。结果监控面板几百个指标,真正出问题时,反而找不到关键信息。
指标分类:RED 和 USE
业界有两个经典的指标分类方法:RED 方法和 USE 方法。
- Rate(请求速率):每秒处理多少请求
- Errors(错误率):请求失败的比例
- Duration(响应时间):请求处理耗时
这三个指标几乎适用于所有对外提供服务的系统。如果你的服务只监控三个东西,就监控这三个。
- Utilization(利用率):资源被使用的程度
- Saturation(饱和度):资源排队等待的程度
- Errors(错误数):资源产生的错误
这个方法适用于 CPU、内存、磁盘、网络等资源型组件。
分层监控:从基础设施到业务
一个完整的监控体系,应该覆盖多个层次:
- CPU 使用率、内存使用率、磁盘 IO
- 网络流量、网络延迟、丢包率
- 机器温度、电源状态
- 数据库连接数、查询响应时间、慢查询
- 缓存命中率、内存使用量
- 消息队列积压量、消费延迟
- 服务可用性、请求量、响应时间
- 错误率、错误类型分布
- 业务指标(如订单量、用户活跃数)
- 页面加载时间、接口可用性
- 用户行为追踪、业务漏斗转化
每一层都有其特定的监控指标,不能遗漏。
指标设计的几个原则
指标的四种类型
在 Prometheus 等监控系统中,指标通常分为四种类型,理解它们对于设计监控非常重要:
- 典型例子:请求总数、错误总数、处理的字节数
- 用途:计算速率(如 QPS)、错误增长趋势
- 注意:Counter 重启会归零,所以要看增长率而不是绝对值
- 典型例子:当前温度、当前内存使用量、队列长度
- 用途:反映系统当前状态
- 注意:Gauge 的值直接使用,不需要计算速率
- 典型例子:请求延迟分布、响应大小分布
- 用途:计算百分位数(P50、P95、P99)
- 注意:能回答"99% 的请求延迟在多少以内"
- 典型例子:流式计算场景下的延迟统计
- 用途:精确的百分位数,但不可聚合
- 注意:通常推荐使用 Histogram,因为它支持跨实例聚合
三、告警策略
监控数据收集上来了,接下来就是告警。但告警是最容易出问题的地方。
告警的困境
很多人都有过这样的经历:告警短信一天收到几十条,大部分是无关紧要的,最后干脆把告警屏蔽了。
这就是告警疲劳。当告警太多时,人会麻木,真正重要的告警反而被忽略。
好的告警系统,不是告警越多越好,而是每个告警都有价值。
告警分级
解决告警疲劳的第一步是告警分级。不是所有问题都需要立即处理。
- 核心服务完全不可用
- 数据丢失或严重错误
- 安全事件
- 响应时间:5分钟内
- 服务响应时间严重下降
- 部分功能不可用
- 资源使用率接近极限
- 响应时间:30分钟内
- 某些非核心服务异常
- 资源使用率较高
- 出现少量错误
- 响应时间:4小时内
- 性能轻微波动
- 非关键指标异常
- 响应时间:下一个工作日
不同级别的告警,通知方式也不同:
- P0(紧急):飞书机器人 + 短信 + 电话
- P1(严重):飞书机器人 + 短信
- P2(一般):飞书机器人
- P3(提示):飞书机器人(工作时间)
告警规则设计原则
好的告警规则是监控系统的核心。设计告警规则时,需要遵循几个关键原则:
告警规则配置示例
以下是一些常见场景的告警规则配置示例(以 Prometheus AlertManager 格式为例):
# 服务可用性告警
- alert: ServiceDown
expr: up{job="order-service"} == 0
for: 1m
labels:
severity: critical
priority: P0
annotations:
summary: "订单服务不可用"
description: "订单服务 {{ $labels.instance }} 已经宕机超过 1 分钟"
# 响应时间告警
- alert: HighLatency
expr: histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{job="order-service"}[5m]))
by (le)) > 1
for: 5m
labels:
severity: warning
priority: P1
annotations:
summary: "订单服务响应时间过高"
description: "P99 延迟 {{ $value | printf \"%.2f\" }}s,超过 1s 阈值"
# 错误率告警
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{job="order-service",status=~"5.."}[5m]))
/ sum(rate(http_requests_total{job="order-service"}[5m])) > 0.05
for: 5m
labels:
severity: critical
priority: P0
annotations:
summary: "订单服务错误率过高"
description: "5xx 错误率 {{ $value | printf \"%.2%%\" }},超过 5% 阈值"
# 资源使用率告警
- alert: HighMemoryUsage
expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) > 0.9
for: 10m
labels:
severity: warning
priority: P1
annotations:
summary: "内存使用率过高"
description: "节点 {{ $labels.instance }} 内存使用率 {{ $value | printf \"%.1%%\" }}"
告警聚合与抑制
# AlertManager 分组配置
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s # 等待 30 秒收集同组告警
group_interval: 5m # 同组新告警的发送间隔
repeat_interval: 4h # 重复告警的发送间隔
# 当集群不可用时,抑制该集群下所有服务的告警
inhibit_rules:
- source_match:
alertname: 'ClusterDown'
target_match_re:
alertname: '.+'
equal: ['cluster']
飞书机器人集成
我们的告警系统集成了飞书机器人,实现了快速、可靠的告警通知。
# AlertManager 飞书 webhook 配置
receivers:
- name: 'feishu-default'
webhook_configs:
- url: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx'
send_resolved: true # 问题解决后也发送通知
- name: 'feishu-critical'
webhook_configs:
- url: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx'
send_resolved: true
{
"msg_type": "interactive",
"card": {
"header": {
"title": {
"content": "🚨 P0告警:订单服务不可用",
"tag": "plain_text"
},
"template": "red"
},
"elements": [
{
"tag": "div",
"text": {
"content": "**告警级别**:P0(紧急)\n**影响范围**:所有用户无法下单\n**持续时间**:3分钟\n**当前QPS**:0(正常值:1500)",
"tag": "lark_md"
}
},
{
"tag": "action",
"actions": [
{
"tag": "button",
"text": {
"content": "查看Grafana",
"tag": "plain_text"
},
"url": "https://grafana.example.com/d/order-service",
"type": "default"
},
{
"tag": "button",
"text": {
"content": "确认告警",
"tag": "plain_text"
},
"url": "https://alertmanager.example.com/#/alerts",
"type": "primary"
}
]
}
]
}
}
# 分级告警路由
route:
receiver: 'feishu-default'
routes:
- match:
severity: critical
priority: P0
receiver: 'feishu-sms-phone'
- match:
severity: warning
priority: P1
receiver: 'feishu-sms'
receivers:
- name: 'feishu-default'
webhook_configs:
- url: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxx'
- name: 'feishu-sms'
webhook_configs:
- url: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxx'
# 集成短信服务
sms_configs:
- to: '13800138000'
body: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'
- name: 'feishu-sms-phone'
webhook_configs:
- url: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxx'
# 集成短信和电话服务
sms_configs:
- to: '13800138000'
phone_configs:
- to: '13800138000'
# 语音电话告警
避免告警风暴
告警风暴是最可怕的事情。某个核心服务挂了,瞬间触发几百条告警,值班人员的手机被打爆,反而无法快速定位问题。
防止告警风暴的方法:
- 告警去重:同一个问题在短时间内只告警一次
- 告警静默:某些告警可以被手动静默一段时间
- 告警聚合:相关的告警合并成一个
- 分级处理:低级别告警不发送通知,只在系统里记录
- 设置告警预算:限制每个服务/团队的告警数量,超过阈值需要优化
告警升级机制
当告警长时间未处理时,需要有升级机制:
# 告警升级配置示例
escalation:
- after: 15m
if_severity: [P0]
action:
- notify: oncall-lead
- notify: manager
- after: 30m
if_severity: [P0, P1]
action:
- notify: director
- create_incident
数据采集的具体实现
了解数据采集的两种模式后,我们来看具体的实现方案:
最常用的方式是在应用中集成 SDK,暴露 /metrics 端点供 Prometheus 拉取。以下是不同语言的常用客户端:
| 语言 | 客户端库 | 特点 |
|---|---|---|
| Java | micrometer-registry-prometheus | Spring Boot 官方支持 |
| Go | prometheus/client_golang | 官方维护,性能优秀 |
| Python | prometheus_client | 简单易用 |
| Node.js | prom-client | 社区活跃 |
一个简单的 Go 应用指标暴露示例:
package main
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
var (
// 定义 Counter 指标
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path", "status"},
)
// 定义 Histogram 指标
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10},
},
[]string{"method", "path"},
)
)
func init() {
prometheus.MustRegister(httpRequestsTotal)
prometheus.MustRegister(httpRequestDuration)
}
func main() {
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8080", nil)
}
使用 Exporter 将基础设施的指标转换为 Prometheus 格式:
# prometheus.yml 配置示例
scrape_configs:
# Node Exporter - 主机指标
- job_name: 'node-exporter'
static_configs:
- targets: ['10.0.1.1:9100', '10.0.1.2:9100']
# MySQL Exporter - 数据库指标
- job_name: 'mysql-exporter'
static_configs:
- targets: ['10.0.2.1:9104']
# Redis Exporter - 缓存指标
- job_name: 'redis-exporter'
static_configs:
- targets: ['10.0.3.1:9121']
# 应用服务 - 自动发现
- job_name: 'app-services'
consul_sd_configs:
- server: 'consul.service.consul:8500'
services: ['app-service']
对于数据库、缓存、消息队列等中间件,需要配置专门的 Exporter:
# MySQL Exporter 配置
DATA_SOURCE_NAME="user:password@(mysql-host:3306)/" \
mysqld_exporter \
--collect.info_schema.processlist \
--collect.info_schema.innodb_metrics \
--collect.perf_schema.eventsstatements
数据降采样与聚合
原始监控数据量非常大,需要进行降采样来节省存储空间。降采样的核心思想是:近期数据保留高精度,远期数据保留低精度。
原始数据(10秒精度) → 保留 7 天
↓ 降采样
1分钟精度数据 → 保留 30 天
↓ 降采样
1小时精度数据 → 保留 1 年
↓ 降采样
1天精度数据 → 永久保留
降采样的聚合方式取决于指标类型:
- Counter 类:取区间内的平均值(如 QPS)
- Gauge 类:取区间内的平均值、最大值、最小值
- Histogram 类:重新计算百分位数
在 Prometheus 中,可以使用 Recording Rules 预计算常用指标:
# recording_rules.yml
groups:
- name: service_metrics
rules:
# 预计算每分钟的请求速率
- record: job:http_requests:rate1m
expr: sum by (job) (rate(http_requests_total[1m]))
# 预计算 P99 延迟
- record: job:http_request_duration:p99_5m
expr: histogram_quantile(0.99,
sum by (job, le) (rate(http_request_duration_seconds_bucket[5m])))
四、监控系统架构
知道了要监控什么、怎么告警,接下来是实现层面的问题:监控系统本身应该怎么设计?
整体架构
一个典型的监控系统架构包含以下组件:
┌─────────────────────────────────────────────────────────────┐
│ 可视化层 │
│ (Grafana / Kibana / 自研 Dashboard) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 告警层 │
│ (AlertManager / PagerDuty / 自研告警) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 存储层 │
│ (Prometheus / InfluxDB / VictoriaMetrics / Thanos) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 采集层 │
│ (Exporters / StatsD / OpenTelemetry / 自定义 Agent) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 数据源 │
│ (应用 / 中间件 / 基础设施 / 云服务 / 业务系统) │
└─────────────────────────────────────────────────────────────┘
数据采集
监控的第一步是数据采集。主要有两种方式:
- 优点:实时性好,配置灵活,适合短暂运行的批处理任务
- 缺点:组件需要集成 SDK,有侵入性;需要考虑数据上报的可靠性
- 典型工具:StatsD、Telegraf、OpenTelemetry SDK
- 适用场景:应用层监控、短生命周期任务
- 优点:组件无感知,只需暴露 HTTP 接口;服务发现更简单
- 缺点:实时性稍差(取决于拉取间隔);不适合 NAT 后的实例
- 典型工具:Prometheus
- 适用场景:长期运行的服务、基础设施监控
实际应用中,两种模式经常混用。基础设施层多用拉模式,应用层多用推模式。现在业界趋势是采用 OpenTelemetry 统一标准,它支持两种模式,并能同时收集指标、日志和链路追踪。
数据存储
监控数据的特点是:写入量大、查询频繁、有时效性。
时序数据库是监控数据的最佳选择。相比传统数据库,时序数据库针对时间序列数据做了专门优化:
- 写入性能极高,支持每秒百万级数据点
- 支持高效的时间范围查询
- 支持数据降采样,自动压缩历史数据
- 支持数据过期,自动删除过老的数据
| 数据库 | 特点 | 适用场景 |
|---|---|---|
| Prometheus | 单机性能好,生态丰富 | 中小规模集群 |
| VictoriaMetrics | 兼容 Prometheus,性能更高 | 大规模部署 |
| InfluxDB | 功能全面,有商业版 | 需要企业级支持 |
| Thanos | Prometheus 集群方案 | 多集群、长期存储 |
| M3DB | Uber 开源,大规模场景 | 超大规模监控 |
- 原始数据(10s 精度):保留 7 天
- 降采样数据(1min 精度):保留 30 天
- 聚合数据(1h 精度):保留 1 年
这样既保证近期数据的精度,又控制了存储成本。
数据展示
监控数据收集上来后,需要可视化展示。一个好的监控面板应该:
第一层:业务大盘
├── 核心业务指标(订单量、GMV、转化率)
├── 系统健康度(服务可用性、错误率)
└── 关键资源使用情况
第二层:服务面板(按服务分类)
├── 请求量、延迟、错误率
├── 依赖服务状态
└── 资源使用情况
第三层:实例面板(按实例分类)
├── 单实例详细指标
├── 日志链接
└── 链路追踪入口
高可用设计
监控系统自身也需要高可用,否则它挂了,你就两眼一抹黑。
- 使用多个采集器,负载均衡
- 本地缓存数据,防止网络抖动丢失
- 数据复制(至少 2 副本)
- 跨机房部署,防止单机房故障
- AlertManager 集群部署
- 多通知渠道备份(短信失败走电话)
- 监控自身的指标采集是否正常
- 监控数据是否有延迟
- 监控告警是否发送成功
五、故障排查流程
有了监控和告警,当问题发生时,该如何排查?
故障排查的黄金时间
故障发生后,每一秒都很宝贵。前 5 分钟是黄金时间,这个阶段的操作决定了故障恢复的速度。
黄金时间内要做的事:
- 确认问题:通过监控确认问题的范围和严重程度
- 止损优先:如果问题在扩大,先想办法止损(限流、降级、回滚)
- 保留现场:收集日志、dump、快照等信息
- 通知相关方:让需要知道的人知道(用户、老板、相关团队)
排查思路:从外到内
故障排查的核心思路是:从外到内,逐层定位。
- 用户能正常访问吗?(检查 CDN、DNS)
- 哪些功能受影响?
- 影响范围有多大?(全量 vs 部分)
- 哪个服务出了问题?(通过错误率、延迟判断)
- 错误日志是什么?(搜索关键错误信息)
- 最近的变更是什么?(代码发布、配置变更)
- 数据库正常吗?(连接数、慢查询、锁等待)
- 缓存正常吗?(命中率、内存使用)
- 消息队列正常吗?(积压量、消费延迟)
- 网络正常吗?(带宽、延迟、丢包)
- 机器资源够吗?(CPU、内存、磁盘)
- 有没有硬件故障?(查看系统日志)
每一层都要看监控数据,而不是凭感觉猜测。
实战案例:一个慢查询问题的排查
- 确认问题范围:查看监控面板,发现订单服务的 P99 延迟从 100ms 飙升到 3s,错误率从 0.1% 上升到 5%。
- 定位问题服务:通过链路追踪发现,慢请求都卡在数据库查询上。
- 分析数据库:查看数据库监控,发现某条 SQL 的执行时间从 10ms 变成了 2s+。
- 找到根因:查看慢查询日志,发现是一条新上线的 SQL 没有走索引:
SELECT * FROM orders WHERE DATE(created_at) = '2026-02-28'
这个查询对 created_at 字段使用了函数,导致索引失效,全表扫描。
- 临时止血:紧急回滚上一个版本的代码。
- 永久修复:修改 SQL,改为范围查询,走索引:
SELECT * FROM orders
WHERE created_at >= '2026-02-28 00:00:00'
AND created_at < '2026-03-01 00:00:00'
- 复盘改进:
- 增加数据库慢查询告警(>500ms 告警) - 在测试环境添加生产级别的数据量
故障复盘
故障恢复后,事情还没结束。还要做故障复盘。
故障复盘的核心是:找到根本原因,制定预防措施。
一个完整的故障复盘应该包括:
- 故障概况:什么时间、什么问题、影响范围
- 时间线:故障发生、发现、处理、恢复的时间点
- 根因分析:为什么会发生这个问题(用 5 Whys 方法)
- 处理过程:做了什么操作,效果如何
- 经验教训:学到了什么,哪里可以做得更好
- 改进措施:后续要做什么改进,谁来负责,什么时候完成
复盘不是追责大会,而是学习机会。好的复盘文化是:对事不对人,关注改进而不是惩罚。
六、可观测性最佳实践
命名规范
好的指标命名能让监控更易维护:
# 推荐格式
<namespace>_<subsystem>_<name>_<unit>
# 示例
http_requests_total # HTTP 请求总数
http_request_duration_seconds # HTTP 请求延迟(秒)
db_connections_active # 活跃数据库连接数
queue_messages_pending # 队列待处理消息数
- 使用小写和下划线
- 包含单位(seconds、bytes、total)
- 保持一致性(同类指标用相同的后缀)
标签设计
标签(Labels)是指标的多维度信息,好的标签设计能提高查询效率:
# 好的标签设计
http_requests_total{
method="POST",
path="/api/orders",
status="200",
service="order-service",
instance="10.0.1.1:8080"
}
- 标签值应该是有限的(不要用 user_id 作为标签)
- 避免高基数标签(会导致存储爆炸)
- 保持标签的一致性
仪表盘标准化
建立标准化的仪表盘模板,让所有服务使用统一的展示风格:
# 标准服务仪表盘结构
1. 概览行
- 服务状态(红/黄/绿)
- 请求量趋势
- 错误率趋势
- P99 延迟趋势
2. 详细指标
- RED 指标详细图表
- 资源使用情况
- 依赖服务状态
3. 业务指标
- 核心业务指标
- 转化漏斗
- 用户活跃度
4. 链接区
- 跳转到日志
- 跳转到链路追踪
- 跳转到相关服务
监控即代码
把监控配置也当作代码管理,纳入版本控制:
monitoring/
├── rules/
│ ├── service-alerts.yaml
│ ├── infra-alerts.yaml
│ └── business-alerts.yaml
├── dashboards/
│ ├── service-overview.json
│ └── business-metrics.json
└── recording-rules/
└── precomputed-metrics.yaml
这样做的好处:
- 可以 Code Review
- 可以回滚
- 可以做自动化测试
- 可以做配置漂移检测
SLI/SLO/SLA:监控的业务视角
技术指标固然重要,但最终我们关心的是业务可用性。SLI/SLO/SLA 是把技术指标转化为业务指标的关键概念。
- 衡量服务健康状况的具体指标
- 例子:可用性(99.9%)、延迟(P99 < 100ms)、错误率(< 0.1%)
- 对 SLI 设定的目标值
- 例子:99.9% 的请求在 100ms 内响应
- 对客户的承诺,以及未达成的补偿
- 例子:99.9% 可用性,否则赔偿 10% 费用
传统的阈值告警是"CPU > 80% 就报警",但 SLO 驱动的告警是"如果按照当前错误率,这个月的 SLO 会不达标,就报警"。
这叫做错误预算(Error Budget)告警。假设你的 SLO 是 99.9% 可用性,那么每个月有 43 分钟的"预算"可以出错。当错误预算消耗到 50% 时告警,到 90% 时紧急告警。
# 错误预算告警规则
- alert: ErrorBudgetBurnRate
expr: |
(
sum(rate(http_requests_total{status!~"2.."}[1h]))
/ sum(rate(http_requests_total[1h]))
) > (1 - 0.999) * 24 # 1小时消耗了1天的预算
for: 5m
labels:
severity: critical
annotations:
summary: "错误预算消耗过快,1小时内消耗了1天的预算"
这种告警方式的好处是:它直接关联业务目标,而不是技术指标。CPU 高不高不重要,重要的是会不会影响 SLO。
监控系统的容量规划
监控系统本身也需要容量规划,否则它会成为系统的瓶颈。
每天数据量 = 指标数量 × 每分钟采样点数 × 每个数据点大小 × 60 × 24
示例:
- 1000 个指标
- 每分钟 6 个采样点(10秒采集一次)
- 每个数据点 16 字节
- 每天 = 1000 × 6 × 16 × 60 × 24 ≈ 138 MB/天
保留 30 天原始数据 + 1 年聚合数据 ≈ 4 GB + 500 MB ≈ 4.5 GB
- 使用 Recording Rules 预计算:将复杂查询预先计算好
- 合理设置查询时间范围:避免查询过长时间范围
- 使用标签优化查询:在标签上建立索引,提高查询效率
- 分离读写:将查询请求分流到只读副本
七、总结
监控告警是系统稳定性的基石。没有监控的系统就像在黑暗中行走,你永远不知道前面是坦途还是悬崖。
一个完善的监控体系需要考虑:
监控告警不是一次性工作,而是持续演进的过程。随着系统的发展,监控体系也要不断调整和优化。
- 系列七-1:API 网关:流量的"交通枢纽"
- 系列七-2:配置中心:系统的"控制面板"
- 系列七-3:消息队列:异步的"传送带"
- 系列七-4:服务发现:微服务的"通讯录"
- 系列七-5:监控告警:系统的"健康体检"(本文)
💬 评论 (0)