Skip to content
第 235 / 250 章架构⏱ 12 分钟阅读

第 235 章:系统监控与故障应急

学习目标

  • 立体化监控体系
  • 故障应急响应
  • 容量规划
  • 复盘与改进

一、监控层次

1.1 三大支柱

维度工具例子
指标Prometheus + GrafanaQPS、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.MysqlHealthIndicator
java
@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.class

3.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: true

JVM 仪表板:

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_secISR 收缩
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) ≈ 2315

8.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

动手练习

  1. 部署 Prometheus + Grafana,接入你的应用
  2. 自定义业务监控指标(订单量、金额)
  3. 配置告警规则(5xx 率高 / P99 延迟高)
  4. 模拟一次故障,演练完整应急流程

下一章:第 236 章:数据安全与合规

本站基于 VitePress 构建 · 由 Codebook 团队维护