📖 开场:体检中心
想象医院的体检中心 🏥:
没有监控(后知后觉):
病人:感觉不舒服 😷
↓
去医院检查
↓
医生:癌症晚期 💀
↓
错过最佳治疗时机 ❌
结果:
- 发现太晚 ❌
- 治疗困难 ❌
有监控(防患未然):
体检中心:定期体检 🩺
↓
发现指标异常:血压180(警告)⚠️
↓
立即通知:请到医院就诊 📞
↓
及时治疗,避免恶化 ✅
结果:
- 早发现 ✅
- 早治疗 ✅
- 成本低 ✅
这就是监控系统:系统的体检中心!
🤔 为什么需要监控告警?
问题1:系统故障不知道 💀
没有监控:
服务器宕机 💀
↓
用户无法访问 ❌
↓
用户投诉 📞
↓
你才知道出问题了 😱
有监控:
服务器宕机 💀
↓
监控系统:立即告警 🚨
↓
运维人员:5分钟内修复 ✅
问题2:性能下降不知道 🐌
没有监控:
接口响应时间:从100ms → 5秒
↓
用户体验变差 ❌
↓
用户流失 💔
有监控:
响应时间 > 1秒 → 告警 ⚠️
↓
立即优化 ✅
🎯 核心功能
功能1:指标采集 📥
采集指标:
- 系统指标:CPU、内存、磁盘、网络
- 应用指标:QPS、响应时间、错误率
- 业务指标:订单量、GMV、用户活跃度
功能2:数据存储 💾
时序数据库(Time Series Database):
- InfluxDB
- Prometheus
- OpenTSDB
特点:
- 按时间排序 ✅
- 高效压缩 ✅
- 快速查询 ✅
功能3:告警规则 🚨
告警规则:
1. CPU使用率 > 80%(持续5分钟)
2. 内存使用率 > 90%
3. 磁盘使用率 > 85%
4. 接口响应时间 > 1秒
5. 错误率 > 5%
功能4:告警通知 📢
通知渠道:
- 钉钉机器人 🤖
- 企业微信 💬
- 短信 📱
- 邮件 📧
- 电话 ☎️
🎯 系统架构
监控告警系统架构
┌────────────────────────────────────┐
│ 监控对象 │
│ - 服务器 │
│ - 应用服务 │
│ - 数据库 │
│ - 中间件 │
└──────────────┬─────────────────────┘
│ 上报指标
↓
┌────────────────────────────────────┐
│ 指标采集(Agent) │
│ - node_exporter(系统指标) │
│ - 应用埋点(应用指标) │
└──────────────┬─────────────────────┘
│
↓
┌────────────────────────────────────┐
│ 时序数据库(Prometheus) │
│ - 存储指标数据 │
│ - 聚合查询 │
└──────────────┬─────────────────────┘
│
┌───────┼───────┐
↓ ↓ ↓
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 告警规则 │ │ Grafana │ │AlertMgr │
│ 阈值判断 │ │ 可视化 │ │告警发送 │
└──────────┘ └──────────┘ └──────────┘
↓
┌──────────┐
│ 钉钉通知 │
└──────────┘
🎯 核心设计
设计1:Prometheus监控 ⭐⭐⭐
安装Prometheus
# 下载Prometheus
wget https://github.com/prometheus/prometheus/releases/download/v2.40.0/prometheus-2.40.0.linux-amd64.tar.gz
# 解压
tar -xzf prometheus-2.40.0.linux-amd64.tar.gz
cd prometheus-2.40.0.linux-amd64
# 启动
./prometheus --config.file=prometheus.yml
配置prometheus.yml
# ⭐ Prometheus配置
global:
scrape_interval: 15s # 抓取间隔
evaluation_interval: 15s # 告警规则评估间隔
# ⭐ 告警规则文件
rule_files:
- "rules/*.yml"
# ⭐ 告警管理器
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
# ⭐ 监控目标
scrape_configs:
# 监控Prometheus自己
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# ⭐ 监控服务器(node_exporter)
- job_name: 'node'
static_configs:
- targets:
- '192.168.1.1:9100'
- '192.168.1.2:9100'
- '192.168.1.3:9100'
# ⭐ 监控应用服务
- job_name: 'order-service'
static_configs:
- targets: ['192.168.1.10:8080']
设计2:应用埋点(Micrometer)
引入依赖
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置application.yml
management:
endpoints:
web:
exposure:
include: '*' # 暴露所有端点
metrics:
export:
prometheus:
enabled: true # 启用Prometheus导出
自定义指标
@Service
public class OrderService {
// ⭐ 定义计数器(订单数)
private final Counter orderCounter;
// ⭐ 定义计时器(接口响应时间)
private final Timer orderTimer;
public OrderService(MeterRegistry meterRegistry) {
// 注册计数器
this.orderCounter = Counter.builder("order_total")
.tag("service", "order-service")
.description("订单总数")
.register(meterRegistry);
// 注册计时器
this.orderTimer = Timer.builder("order_create_time")
.tag("service", "order-service")
.description("创建订单耗时")
.register(meterRegistry);
}
/**
* ⭐ 创建订单(埋点)
*/
public Order createOrder(OrderRequest request) {
return orderTimer.record(() -> {
// 创建订单逻辑
Order order = new Order();
// ...
orderMapper.insert(order);
// ⭐ 计数器+1
orderCounter.increment();
return order;
});
}
}
访问指标:
http://localhost:8080/actuator/prometheus
# 输出:
order_total{service="order-service"} 12345
order_create_time_seconds_sum{service="order-service"} 123.456
order_create_time_seconds_count{service="order-service"} 12345
设计3:告警规则
创建rules/alert.yml
groups:
- name: server_alerts
interval: 30s # 评估间隔
rules:
# ⭐ CPU告警
- alert: HighCPU
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m # 持续5分钟
labels:
severity: warning
annotations:
summary: "服务器CPU使用率过高"
description: "{{ $labels.instance }} CPU使用率 {{ $value | humanize }}%"
# ⭐ 内存告警
- alert: HighMemory
expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90
for: 5m
labels:
severity: critical
annotations:
summary: "服务器内存使用率过高"
description: "{{ $labels.instance }} 内存使用率 {{ $value | humanize }}%"
# ⭐ 磁盘告警
- alert: HighDisk
expr: (node_filesystem_size_bytes - node_filesystem_free_bytes) / node_filesystem_size_bytes * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "服务器磁盘使用率过高"
description: "{{ $labels.instance }} 磁盘使用率 {{ $value | humanize }}%"
- name: application_alerts
interval: 30s
rules:
# ⭐ 接口响应时间告警
- alert: SlowAPI
expr: histogram_quantile(0.95, rate(order_create_time_seconds_bucket[5m])) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "接口响应时间过长"
description: "订单创建接口P95响应时间 {{ $value | humanize }}秒"
# ⭐ 错误率告警
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) * 100 > 5
for: 5m
labels:
severity: critical
annotations:
summary: "接口错误率过高"
description: "错误率 {{ $value | humanize }}%"
设计4:AlertManager告警管理
安装AlertManager
# 下载
wget https://github.com/prometheus/alertmanager/releases/download/v0.25.0/alertmanager-0.25.0.linux-amd64.tar.gz
# 解压
tar -xzf alertmanager-0.25.0.linux-amd64.tar.gz
cd alertmanager-0.25.0.linux-amd64
# 启动
./alertmanager --config.file=alertmanager.yml
配置alertmanager.yml
global:
resolve_timeout: 5m # 告警恢复超时时间
# ⭐ 路由规则
route:
group_by: ['alertname'] # 按告警名称分组
group_wait: 10s # 等待10秒收集同组告警
group_interval: 10s # 同组告警间隔10秒
repeat_interval: 1h # 重复告警间隔1小时
receiver: 'dingding' # 默认接收者
# ⭐ 接收者配置
receivers:
- name: 'dingding'
webhook_configs:
- url: 'http://localhost:8060/dingtalk/webhook'
send_resolved: true # 发送恢复通知
设计5:钉钉告警通知
代码实现
@RestController
@RequestMapping("/dingtalk")
public class DingTalkWebhook {
private String webhookUrl = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN";
@Autowired
private RestTemplate restTemplate;
/**
* ⭐ 接收AlertManager Webhook
*/
@PostMapping("/webhook")
public void receiveAlert(@RequestBody AlertManagerWebhook webhook) {
List<Alert> alerts = webhook.getAlerts();
for (Alert alert : alerts) {
String alertName = alert.getLabels().get("alertname");
String severity = alert.getLabels().get("severity");
String summary = alert.getAnnotations().get("summary");
String description = alert.getAnnotations().get("description");
String status = alert.getStatus(); // firing/resolved
// ⭐ 构造钉钉消息
String message = String.format(
"## %s告警%s\n\n" +
"**级别**: %s\n\n" +
"**摘要**: %s\n\n" +
"**详情**: %s\n\n" +
"**时间**: %s",
status.equals("firing") ? "🚨" : "✅",
status.equals("firing") ? "" : "恢复",
severity,
summary,
description,
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())
);
// 发送到钉钉
sendToDingTalk(message);
}
}
/**
* ⭐ 发送钉钉消息
*/
private void sendToDingTalk(String content) {
Map<String, Object> request = new HashMap<>();
request.put("msgtype", "markdown");
Map<String, String> markdown = new HashMap<>();
markdown.put("title", "监控告警");
markdown.put("text", content);
request.put("markdown", markdown);
restTemplate.postForObject(webhookUrl, request, String.class);
}
}
🎓 面试题速答
Q1: 监控系统有哪些组件?
A: 三大组件:
-
Prometheus(时序数据库):
- 存储指标数据
- 执行告警规则
-
AlertManager(告警管理):
- 告警聚合
- 告警降噪
- 告警路由
-
Grafana(可视化):
- 指标展示
- Dashboard
Q2: 如何采集应用指标?
A: Micrometer埋点:
// 引入依赖
micrometer-registry-prometheus
spring-boot-starter-actuator
// 自定义指标
Counter counter = Counter.builder("order_total")
.register(meterRegistry);
counter.increment(); // 计数器+1
// 访问指标
http://localhost:8080/actuator/prometheus
Q3: 告警规则如何配置?
A: PromQL表达式:
# CPU告警
- alert: HighCPU
expr: 100 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 > 80
for: 5m # 持续5分钟
含义:CPU使用率 > 80%,持续5分钟触发告警
Q4: 如何避免告警风暴?
A: 四种降噪策略:
-
分组聚合:
- 同类告警合并发送
-
抑制规则:
- 高优先级告警触发时,抑制低优先级
-
静默规则:
- 维护期间暂停告警
-
重复间隔:
- 1小时内不重复发送
Q5: 监控指标有哪些?
A: 四大黄金指标:
-
延迟(Latency):
- 接口响应时间
-
流量(Traffic):
- QPS、TPS
-
错误(Errors):
- 错误率、错误数
-
饱和度(Saturation):
- CPU、内存、磁盘使用率
Q6: 时序数据库的特点?
A: 三大特点:
-
按时间排序:
- 时间戳是主键
-
高效压缩:
- 1000个数据点 → 12字节
-
快速聚合:
- avg、sum、rate等
例子:
Prometheus查询:
rate(http_requests_total[5m]) # 最近5分钟的QPS
🎬 总结
监控告警系统核心
┌────────────────────────────────────┐
│ 1. Prometheus(时序数据库)⭐ │
│ - 指标采集 │
│ - 数据存储 │
│ - 告警规则 │
└────────────────────────────────────┘
┌────────────────────────────────────┐
│ 2. 应用埋点(Micrometer) │
│ - Counter(计数器) │
│ - Timer(计时器) │
│ - Gauge(仪表盘) │
└────────────────────────────────────┘
┌────────────────────────────────────┐
│ 3. 告警规则(PromQL) │
│ - CPU > 80% │
│ - 内存 > 90% │
│ - 响应时间 > 1秒 │
└────────────────────────────────────┘
┌────────────────────────────────────┐
│ 4. AlertManager(告警管理) │
│ - 告警聚合 │
│ - 告警降噪 │
│ - 告警路由 │
└────────────────────────────────────┘
┌────────────────────────────────────┐
│ 5. 钉钉通知 │
│ - Webhook接收告警 │
│ - Markdown格式 │
└────────────────────────────────────┘
🎉 恭喜你!
你已经完全掌握了监控告警系统的设计!🎊
核心要点:
- Prometheus:时序数据库,指标采集和存储
- Micrometer:应用埋点,自定义指标
- 告警规则:PromQL表达式,阈值判断
- AlertManager:告警聚合、降噪、路由
- 钉钉通知:Webhook接收,Markdown格式
下次面试,这样回答:
"监控系统采用Prometheus + AlertManager + Grafana架构。Prometheus作为时序数据库,负责指标采集、存储和告警规则评估。应用服务集成Micrometer和Actuator,暴露/actuator/prometheus端点,Prometheus定时拉取指标数据。
应用埋点使用Micrometer自定义指标。创建Counter计数器统计订单数,Timer计时器统计接口响应时间。这些指标按Prometheus格式导出,Prometheus每15秒拉取一次。系统指标使用node_exporter采集,包括CPU、内存、磁盘、网络等。
告警规则使用PromQL表达式配置。例如CPU告警规则:100减去idle模式CPU比例的5分钟平均值,大于80%且持续5分钟触发告警。接口响应时间告警:P95分位数超过1秒触发。错误率告警:5xx错误占比超过5%触发。
AlertManager负责告警管理。接收Prometheus告警后,按alertname分组,等待10秒收集同组告警再发送,避免告警风暴。配置重复间隔1小时,防止频繁发送。通过Webhook发送到钉钉机器人,使用Markdown格式展示告警信息,包括级别、摘要、详情和时间。
可视化使用Grafana展示。导入Prometheus数据源,创建Dashboard展示CPU、内存、QPS、响应时间等指标。配置告警Panel,直观看到当前告警数量。监控四大黄金指标:延迟、流量、错误和饱和度,全面掌握系统健康状况。"
面试官:👍 "很好!你对监控系统的设计理解很深刻!"
本文完 🎬
上一篇: 219-设计一个推荐系统架构.md
下一篇: 221-设计一个电商库存系统.md
作者注:写完这篇,我觉得自己可以当运维工程师了!📊
如果这篇文章对你有帮助,请给我一个Star⭐!