第 235 章:系统监控与故障应急
学习目标
- 立体化监控体系
- 故障应急响应
- 容量规划
- 复盘与改进
一、监控层次
1.1 三大支柱
| 维度 | 工具 | 例子 |
|---|---|---|
| 指标 | Prometheus + Grafana | QPS、P99、内存 |
| 日志 | ELK / Loki | 错误日志、堆栈 |
| 追踪 | SkyWalking / Zipkin | 调用链 |
1.2 监控层级
二、应用层监控
2.1 关键指标
| 类别 | 指标 |
|---|---|
| 流量 | QPS、TPS、连接数 |
| 性能 | RT(P50/P90/P99)、慢 SQL 占比 |
| 可用性 | 错误率、5xx 占比、超时率 |
| 资源 | JVM(堆/线程/GC)、CPU、Memory |
| 业务 | 下单数、支付数、转化率 |
2.2 Micrometer 自定义指标
java
@Component
public class BusinessMetrics {
private final Counter orderCounter;
private final Timer orderTimer;
private final DistributionSummary amountSummary;
public BusinessMetrics(MeterRegistry registry) {
this.orderCounter = Counter.builder("orders.count")
.tag("status", "all")
.register(registry);
this.orderTimer = Timer.builder("order.process")
.register(registry);
this.amountSummary = DistributionSummary.builder("order.amount")
.baseUnit("yuan")
.register(registry);
}
public void onCreate(Order order) {
orderCounter.increment();
amountSummary.record(order.getAmount().doubleValue());
}
public void onProcess(Runnable r) {
Timer.Sample sample = Timer.start();
try {
r.run();
} finally {
sample.stop(orderTimer);
}
}
}2.3 健康检查
yaml
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
health:
db:
enabled: true
redis:
enabled: true
diskSpace:
enabled: true
custom:
mysql-master: com.example.indicator.MysqlHealthIndicatorjava
@Component("mysql-master")
public class MysqlHealthIndicator implements HealthIndicator {
@Override
public Health health() {
try (Connection conn = dataSource.getConnection()) {
if (conn.isValid(2)) {
return Health.up()
.withDetail("version", conn.getMetaData().getDatabaseProductVersion())
.build();
}
return Health.down().build();
} catch (Exception e) {
return Health.down(e).build();
}
}
}三、JVM 监控
3.1 关键指标
| 指标 | 含义 | 警戒 |
|---|---|---|
| Heap | 堆使用 | > 80% 警戒 |
| GC 次数 | 单位时间 GC | > 10/min 异常 |
| STW 时长 | Stop The World | > 200ms 异常 |
| 线程数 | 活跃线程 | 突变 |
| 死锁 | 死锁线程数 | 0 必须 |
3.2 Arthas 实战
bash
# 启动 arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# dashboard
dashboard
# 线程
thread -n 3
# 死锁检测
thread
# 反编译
jad com.example.OrderService
# watch 命令
watch com.example.OrderService create '{params, returnObj, throwExp}' -x 5
# trace 慢路径
trace com.example.OrderService create '#cost > 100'
# 在线热更新
jad com.example.OrderService
mc /tmp/OrderService.java -d /tmp
retransform /tmp/com/example/OrderService.class3.3 Prometheus 抓取 JVM
yaml
spring:
application:
name: order-service
management:
endpoints:
web:
exposure:
include: "*"
metrics:
tags:
application: ${spring.application.name}
distribution:
percentiles-histogram:
order.process: trueJVM 仪表板:
json
{
"panels": [
{
"title": "Heap Usage",
"targets": [{
"expr": "sum(jvm_memory_used_bytes{application='order-service', area='heap'}) / sum(jvm_memory_max_bytes{application='order-service', area='heap'})"
}]
},
{
"title": "GC 次数/分",
"targets": [{
"expr": "rate(jvm_gc_pause_seconds_count{application='order-service'}[1m]) * 60"
}]
}
]
}四、中间件监控
4.1 Redis
bash
# 客户端
redis-cli info
# memory / stats / replication / commandstats
# 慢查询
SLOWLOG GET 10
# 大 key
redis-cli --bigkeys| 指标 | 警戒 |
|---|---|
| used_memory | < 70% maxmemory |
| connected_clients | 与连接池匹配 |
| ops/sec | 监控突变 |
| slow log | > 5 ms 视为慢 |
| 碎片率 | > 1.5 警戒 |
4.2 MQ(Kafka)
| 指标 | 说明 |
|---|---|
| under_replicated_partitions | 副本不健康 |
| consumer lag | 消费者落后 |
| messages_in_per_sec | 入量 |
| isr_shrink_per_sec | ISR 收缩 |
| network_io | 网络流量 |
4.3 MySQL
sql
SHOW STATUS LIKE 'Threads%';
SHOW STATUS LIKE 'Innodb%';
SHOW PROCESSLIST;
EXPLAIN your_query;| 指标 | 警戒 |
|---|---|
| QPS | 监控 |
| 慢查询数/秒 | 警戒 |
| InnoDB row lock time | > 100ms |
| Threads_created | 持续增长 → 线程池问题 |
| 连接数 | < maxConnections |
4.4 自定义健康探针
java
@Component
public class CustomHealthCheck implements HealthIndicator {
@Override
public Health health() {
// 1. 关键路径探活
try {
inventoryService.ping();
paymentService.ping();
return Health.up().build();
} catch (Exception e) {
return Health.down().withException(e).build();
}
}
}五、业务监控
5.1 大屏监控
5.2 业务异常监控
java
@Component
public class OrderExceptionMonitor {
private final Counter bizExceptionCounter;
private final Map<String, AtomicInteger> hourlyStats = new ConcurrentHashMap<>();
public OrderExceptionMonitor(MeterRegistry registry) {
this.bizExceptionCounter = Counter.builder("biz.exception")
.tag("service", "order")
.register(registry);
}
public void onException(String type, Exception e) {
bizExceptionCounter.increment();
hourlyStats.computeIfAbsent(type, k -> new AtomicInteger(0)).incrementAndGet();
}
}5.3 实时统计
java
// 通过 Kafka Stream 实时统计
KStream<String, OrderEvent> stream = ...;
stream
.filter((k, v) -> v instanceof OrderPaidEvent)
.groupByKey()
.windowedBy(TimeWindows.of(Duration.ofMinutes(5)))
.count()
.toStream()
.foreach((k, v) -> dashboard.push("paid_orders", v));六、告警体系
6.1 分级
| 级别 | 响应时间 | 通知 |
|---|---|---|
| P0 宕机 | 5 分钟 | 电话 + 钉钉 + 短信 |
| P1 严重 | 30 分钟 | 钉钉群 |
| P2 警告 | 2 小时 | 邮件 |
| P3 提示 | 下一个工作日 | 工单 |
6.2 告警规则
yaml
# Prometheus AlertManager
groups:
- name: order-service
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status="5xx"}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "5xx 错误率超 5%"
description: "{{ $labels.instance }} 当前 {{ $value | humanizePercentage }}"
- alert: P99Latency
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "P99 延迟 > 1s"6.3 降噪
| 措施 | 实现 |
|---|---|
| 告警合并 | 同服务同指标一窗口合一 |
| 告警抑制 | 严重告警抑制次要 |
| 告警静默 | 例行维护窗口静默 |
| 值班轮换 | 避免一个人常被打扰 |
七、故障应急
7.1 故障响应流程
7.2 应急止损手段
| 手段 | 操作 |
|---|---|
| 重启 | K8s rollout restart |
| 限流 | Sentinel 调阈值 |
| 降级 | 自动降级开关 |
| 回滚 | kubectl rollout undo |
| 切库 | 主从切换(HA) |
| 封接口 | 网关临时屏蔽 |
| 切流量 | DNS / LB 切换 |
7.3 故障案例
案例 1:Redis 大 key 阻塞
bash
# 1. 现场:
- redis-cli slowlog get
- 发现 GET product:detail:... 耗时 500ms
# 2. 临时方案:
- 紧急删除大 key
- DBACCEL hot: ... 回源
# 3. 根治:
- 拆分大 value(HASH 替代)
- 加监控:大 key 告警案例 2:线程池打满
bash
# 1. Arthas 查线程
thread -n 10
# 2. 看到 Tomcat-nio 都在 BLOCKED
# 3. 检查慢 SQL
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE TIME > 5;
# 4. KILL 慢查询
KILL <id>;八、容量规划
8.1 公式
QPS 目标 = 日活 × 每用户请求数 / 峰值占比 / 86400
峰值占比一般按 0.1 计算
例:DAU 100 万,每人每天 10 次,峰值占比 5%
QPS = 1,000,000 × 10 / (86400 × 0.05) ≈ 23158.2 资源计算
应用机器 = QPS × 单机能力 / 利用率
例:目标 5000 QPS,单机 500 QPS,利用 60%
= 5000 / 500 / 0.6 ≈ 17 台8.3 容量压测
bash
# 全链路压测
wrk -t 16 -c 1000 -d 60s -H "X-Test: stress" \
http://gateway/api/orders
# 持续压测,看何时 QPS 反弹 / P99 飙升九、复盘
9.1 复盘模板
【故障基本信息】
开始时间: 2026-08-13 10:00:00
恢复时间: 2026-08-13 11:30:00
影响时长: 1 小时 30 分钟
影响范围: 50% 用户无法下单
损失: 约 200 万元 GMV
【故障原因】
根因: Redis cluster 主节点故障,客户端未配置重连
【timeline】
10:00 Redis 主节点故障
10:01 客户端连接丢失,持续报错
10:05 监控告警
10:10 工程师介入
10:30 临时开启降级
10:45 客户端修复重连
11:00 完成 Redis cluster 重建
11:30 全量恢复
【Action Item】
1. 客户端增加 Sentinel 集群容错 [#A1]
2. Redis 增加主从双写避免瞬断 [#A2]
3. 增加心跳监控,主动发现 [#A3]
4. 演练:故障注入测试 [#A4]9.2 SLO 复盘
yaml
SLO: 99.9% 可用
月度错误预算: 43 分钟
本月已使用: 90 分钟
触发 review,降低发版频率十、SRE 文化
yaml
SRE 实践:
- 错误预算驱动 SLO
- 自动 release / rollback
- on-call 值班
- 故障复盘,无指责
- 持续改进十一、本章小结
| 主题 | 工具 |
|---|---|
| 指标 | Prometheus + Grafana |
| 日志 | ELK / Loki |
| 追踪 | SkyWalking / Zipkin |
| 告警 | AlertManager + 钉钉 |
| 压测 | JMeter / wrk |
| 定位 | Arthas / jstack |
动手练习
- 部署 Prometheus + Grafana,接入你的应用
- 自定义业务监控指标(订单量、金额)
- 配置告警规则(5xx 率高 / P99 延迟高)
- 模拟一次故障,演练完整应急流程
下一章:第 236 章:数据安全与合规