人人都会AI编程

20.4 线上监控体系:指标采集、日志收集、告警机制

更新时间:2026-07-10

应用上线只是第一步,持续掌握应用的运行状态、快速定位问题、在故障发生前及时响应,才是生产环境运维的核心能力。本节构建一套面向 Spring Boot 应用的轻量级、可落地的监控体系,覆盖指标采集、日志收集与告警通知三大模块,确保即使小团队也能做到可观测性不缺失。

20.4.1 指标采集:用 Micrometer 统一暴露应用指标

Spring Boot 默认集成了 Micrometer,它是一套指标门面,能以统一的 API 将 JVM、框架和自定义指标导出到不同的监控后端(Prometheus、InfluxDB、Elasticsearch 等)。常用的采集粒度包括:

  • JVM 指标:内存使用、GC 次数与耗时、线程数、类加载数。
  • HTTP 请求指标:请求次数、响应时间分布、错误率(通过 spring-boot-starter-actuator + 合适的 Web 容器指标)。
  • 数据源指标:HikariCP 连接池的活跃连接数、等待线程数、连接超时次数。
  • 业务自定义指标:订单创建速率、支付成功率、某缓存命中率等。

接入方案:Actuator + Micrometer + Prometheus

  1. 添加依赖(以 Gradle 为例,Maven 同理):
   implementation 'org.springframework.boot:spring-boot-starter-actuator'
   implementation 'io.micrometer:micrometer-registry-prometheus'
   
  1. 暴露端点,在 application.yml 中开放 Prometheus 格式的指标端点:
   management:
     endpoints:
       web:
         exposure:
           include: health,info,prometheus
     metrics:
       tags:
         application: ${spring.application.name}
   

此时访问 /actuator/prometheus 即可看到大量指标数据。

  1. 部署 Prometheus(生产建议使用 Operator 或托管服务),在 prometheus.yml 中添加抓取任务:
   scrape_configs:
     - job_name: 'spring-boot'
       metrics_path: '/actuator/prometheus'
       static_configs:
         - targets: ['app-host:8080']
   
  1. 自定义业务指标示例:使用 MeterRegistry 注入,定义计数器或计时器。
   @RestController
   public class OrderController {
       private final Counter orderCreateCounter;

       public OrderController(MeterRegistry registry) {
           this.orderCreateCounter = Counter.builder("orders.created")
               .description("Number of created orders")
               .register(registry);
       }

       @PostMapping("/orders")
       public void createOrder() {
           // 业务逻辑
           orderCreateCounter.increment();
       }
   }
   

通过这套机制,所有实例的指标被 Prometheus 定期拉取并存储,Grafana 以数据源形式接入 Prometheus,即可用图表直观展示。无需额外改造,Spring Boot 应用就具备了生产级指标输出能力。

20.4.2 日志收集:从 Console 到集中存储与检索

日志是排查问题的第一手资料。微服务实例化后,日志散落在各自的容器/服务器中,必须集中收集才能发挥效用。主流的方案有两种:

  • ELK/EFK 栈:Elasticsearch + Logstash/Fluentd + Kibana,功能强大,适合大日志量和复杂分析场景。
  • Loki 栈:Grafana Loki + Promtail,轻量,原生集成 Grafana,存储成本低,适合中小规模或成本敏感场景。

这里以 EFK(Elasticsearch + Fluentd + Kibana) 为例,展示与 Spring Boot 应用的整合方式。Fluentd 作为采集器,比 Logstash 更轻量,资源占用小,且在 Kubernetes 中部署简便。

步骤一:应用侧输出 JSON 格式日志

为使 Fluentd 高效解析,建议将 Spring Boot 日志格式设置为 JSON。在 logback-spring.xml 中配置 LogstashEncoder(需要 net.logstash.logback:logstash-logback-encoder 依赖):

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>

此时日志将输出含 timestamplevelloggermessage 及 MDC 字段的 JSON 行,便于后续索引。

步骤二:Fluentd 收集并转发到 Elasticsearch

在 Kubernetes 中,通常以 DaemonSet 部署 Fluentd,挂载宿主机日志目录,解析容器标准输出。简单的 fluent.conf 配置片段:

<source>
  @type tail
  path /var/log/containers/*.log
  pos_file /var/log/fluentd-containers.log.pos
  tag kubernetes.*
  <parse>
    @type json
  </parse>
</source>

<match kubernetes.**>
  @type elasticsearch
  host elasticsearch-logging
  port 9200
  logstash_format true
  logstash_prefix spring-app
  include_tag_key true
</match>

Fluentd 将 JSON 日志按天索引至 Elasticsearch,Kibana 即可进行全文检索和可视化。

步骤三:关联指标与日志

在实践中,为了通过一条 Trace ID 或请求 ID 将指标(如慢请求)和日志串起来,需要在请求入口生成唯一标识并放入 MDC,同时在响应头返回。例如使用 Spring Cloud Sleuth 自动注入 traceIdspanId,或在 Filter 中手动设置:

String requestId = UUID.randomUUID().toString().substring(0,8);
MDC.put("requestId", requestId);

在日志 JSON 中此字段会被自动包含,后续排查问题时,只需在 Kibana 中搜索该请求 ID 即可完整还原调用链路。

20.4.3 告警机制:从被动观测到主动响应

光有指标和日志还不够,需要基于它们定义异常规则,让系统在出现异常时自动通知到人。Prometheus + Alertmanager 是目前社区使用最广泛的组合,其告警规则灵活,通知渠道丰富。

Prometheus 告警规则示例

定义延迟和错误率规则,保存为 spring-app-rules.yml 并在 Prometheus 配置中引用:

groups:
- name: spring-application
  rules:
  - alert: HighRequestLatency
    expr: histogram_quantile(0.99, rate(http_server_requests_seconds_bucket[5m])) > 1
    for: 3m
    labels:
      severity: warning
    annotations:
      summary: "P99 latency over 1s (instance {{ $labels.instance }})"
      description: "The 99th percentile latency has been higher than 1 second for 3 minutes"
      
  - alert: ErrorRateHigh
    expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) / rate(http_server_requests_seconds_count[5m]) > 0.05
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "Error rate > 5%"
      description: "Service {{ $labels.application }} has a 5xx error rate of {{ $value | humanizePercentage }}"

Alertmanager 配置通知

Alertmanager 负责接收 Prometheus 推送的告警,去重、分组后路由到邮件、钉钉/飞书/企业微信或 PagerDuty 等。例如配置钉钉群机器人通知(需部署 prometheus-webhook-dingtalk 中间件或使用 Alertmanager 的 webhook 直接调用):

route:
  receiver: 'dingtalk'
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h

receivers:
- name: 'dingtalk'
  webhook_configs:
  - url: 'http://dingtalk-webhook:8060/dingtalk/webhook1/send'
    send_resolved: true

当告警被触发,相关人员会立刻在 IM 工具中收到消息,包含告警摘要、实例信息等。配合 Grafana 仪表板链接,可一键跳转到出问题时段的可视化视图。

告警的实用原则

  • 避免告警风暴:设置合理的 for 持续时间,防止瞬时抖动触发大量告警。
  • 按严重程度分级:warning 级别仅作提醒,critical 则需要立即介入。
  • 告警必须可操作:每一条告警都应能指向具体的排查动作,否则就是噪音。
  • 持续优化:定期回顾告警历史,去除无效告警,调整阈值,使监控真正成为团队的“安全网”。

20.4.4 最小化落地清单

对于资源有限的小团队,不必一次性搭建重型平台,可遵循以下顺序渐进增强:

  1. 所有项目引入 Actuator + Micrometer + Prometheus 依赖,指标端口对外暴露。
  2. 部署单节点 Prometheus + Grafana(Docker 一键启动),导入 Spring Boot 通用仪表板(社区 ID:10254、12900 等),即可看到内存、HTTP 请求等核心指标。
  3. 日志 JSON 化,并输出到 stdout;测试环境使用 docker-compose 启一个 ELK 或 Loki 栈,验证日志集中查询可行性。
  4. 关键接口定义 Prometheus 告警规则,配置 Alertmanager 发送到企业微信群机器人,确保有人接收到。

当这套基础监控成型后,再逐步引入分布式链路追踪(如 SkyWalking 或 Zipkin)、更复杂的分位数告警、基于日志的异常检测等,形成纵深防御式的可观测体系。

线上环境不可控,但监控可以预测。有了上述组合拳,应用的任何健康波动都将变成可感知、可追查、可行动的信号,而不是生产事故后的追悔莫及。