CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
可观测性入门/课时/Spring 可观测性
RawBlame
课时目录12 节

可观测性入门

  1. 01可观测性三支柱
  2. 02指标与 SLI
  3. 03结构化日志
  4. 04分布式链路追踪
  5. 05插桩与埋点
  6. 06监控与告警
  7. 07遥测与 OpenTelemetry
  8. 08Spring 可观测性
  9. 09SLO 与错误预算
  10. 10仪表盘设计
  11. 11故障排查流程
  12. 12综合练习

Spring 可观测性

Actuator、Micrometer;对照 prom-spring。

30 分钟

Spring 可观测性

这一课你将能做到

  1. 为判题 backend 配置 Actuator,暴露 health、prometheus、metrics 端点,并说明生产为何不能 include: *
  2. 理解 Micrometer 自动注册的 HTTP、JVM、数据源、Kafka 指标,并会加一个判题业务的低基数 Timer/Counter
  3. 把 Actuator 与 K8s 探针、Prometheus scrape、结构化日志中的 traceId、OTel agent 的分工关系理清楚

为什么要学

判题 backend 基于 Spring Boot:可观测性主路径是 Actuator + Micrometer(健康检查、指标),链路常接 OTel agent 或 Spring Cloud Sleuth。但生产环境的 Actuator 配置错误是高频安全事件来源——有人把 management.endpoints.web.exposure.include: "*" 直接上线,heapdump、env、beans 端点全裸奔,攻击者可以直接下载堆 dump 拿到所有密钥。

面试里「Actuator 生产环境怎么配」「health 指示器怎么设计」「Micrometer 和 Prometheus 什么关系」是高频题。本课对照 prom-spring 的 registry 视角,但焦点是 Spring 应用侧如何暴露与埋点;Actuator 安全基础见 sb-actuator。

先建立图像

端点用途生产注意
/actuator/health存活/就绪;可含 DB、Kafka 等组件状态细节不对公网裸奔
/actuator/prometheusPrometheus 文本格式指标内网或鉴权
/actuator/metrics单指标 JSON 查看(排障用)内网或鉴权
/actuator/env、/actuator/heapdump环境变量、堆 dump禁止生产暴露
一次判题提交的 Spring 侧观测面:

POST /api/judge/submissions
    │
    ├─ Micrometer Timer(http.server.requests,含 uri/method/status)
    ├─ Actuator /prometheus ←── Prometheus scrape(15s 间隔)
    ├─ health indicators ←── K8s liveness/readiness 探针
    ├─ 日志 MDC(traceId) ←── OTel agent 过滤器
    ├─ 手动 Counter(judge_submissions_total{language="java"})
    └─ DataSource/Kafka 自动指标 ←── Micrometer 插桩

跟着做

步骤 1:加入依赖

<!-- 将 Micrometer 指标以 Prometheus 格式暴露 -->
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

应得到:classpath 具备 Prometheus registry;尚需配置暴露端点。

步骤 2:配置暴露面与公共标签(生产底线)

management: endpoints: web: exposure: # 生产显式白名单;绝对禁止 include: "*" include: health,prometheus,metrics,info base-path: /actuator endpoint: health: show-details: when_authorized # 细节只对认证用户展示 metrics: tags: application: coderoadmap-backend # 聚合用低基数公共标签 region: cn-hangzhou

安全底线三条:

  1. 白名单暴露:只开 health,prometheus,metrics,info
  2. 端口隔离:生产可配 management.server.port: 9091,与业务端口分开,用网络策略限制访问
  3. 鉴权:Spring Security 保护 /actuator/**,或只允许内网 IP

应得到:知道「暴露哪些」与「如何按应用聚合」。

步骤 3:本地验证 prometheus 端点

# 查 JVM 内存指标(Windows 用 findstr,Linux 用 grep)
curl -s http://localhost:8080/actuator/prometheus | findstr jvm_memory_used_bytes

# 查健康状态
curl -s http://localhost:8080/actuator/health

# 查单个指标(如 HTTP 请求计数)
curl -s "http://localhost:8080/actuator/metrics/http.server.requests"

应看到:JVM 内存指标行;health 返回 UP/DOWN JSON;metrics 返回具体数值。scrape 配置细节见 prom-scrape。

步骤 4:给判题接口加业务埋点

@RestController
@RequestMapping("/api/judge")
public class JudgeController {

    private final JudgeService judgeService;
    private final MeterRegistry registry;

    public JudgeController(JudgeService judgeService, MeterRegistry registry) {
        this.judgeService = judgeService;
        this.registry = registry;
    }

    @PostMapping("/submissions")
    public SubmissionDto submit(@RequestBody SubmitRequest req) {
        // 业务计数:标签只用有界枚举
        registry.counter("judge_submissions_total",
                "language", req.getLanguage())   // java/python/cpp,3~5 种
            .increment();
        return judgeService.submit(req);
    }
}

在 JudgeService 给判题创建耗时加 Timer:

public SubmissionDto submit(SubmitRequest req) {
    return Timer.builder("judge_submission_create")
        .description("判题创建耗时")
        .register(registry)
        .record(() -> doSubmit(req));  // 写库 + 投递 Kafka
}

启动后访问 /actuator/prometheus,搜索 judge_submissions_total 和 judge_submission_create_seconds 应能看到对应行。

步骤 5:设计 health 指示器——判题关键依赖

判题 backend 的健康不只看「进程活着」,还要看关键依赖是否真的可用:

management:
  health:
    db:
      enabled: true
    redis:
      enabled: true
    kafka:
      enabled: true
    # 关键:readiness 要包含所有关键依赖
    probes:
      enabled: true
    group:
      readiness:
        include: db,redis,kafka,diskSpace
      liveness:
        include: ping  # 存活只看进程本身,避免因依赖抖动被误杀

分工原则:

  • Liveness:只检查进程本身(ping),DB 挂了不该让 K8s 重启容器——重启解决不了 DB 问题,反而导致 cascading failure
  • Readiness:检查所有关键依赖(DB、Redis、Kafka),任何一个挂了 K8s 摘流,防止请求打到一个「活着但已残废」的实例

见 kubernetes-essentials、reliability-essentials。

步骤 6:日志关联 traceId

确认 OTel agent 或 Sleuth 把 traceId 放入 MDC,JSON 日志能搜到:

{
  "timestamp": "2026-10-07T10:30:15.123",
  "level": "INFO",
  "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
  "spanId": "00f067aa0ba902b7",
  "logger": "com.coderoadmap.judge.JudgeService",
  "message": "提交创建成功 submissionId=12345 language=java"
}

排障时:Grafana 面板发现 P99 突增 → 复制 traceId → Loki 查日志 → 定位到具体 submission 和慢 SQL。见 obs-logs。

步骤 7:验证 Kafka 和 DataSource 自动指标

Micrometer 会自动注册:

# Kafka producer 指标(投递耗时、失败率)
curl -s http://localhost:8080/actuator/prometheus | findstr kafka_producer

# DataSource 连接池指标(活跃连接、等待线程)
curl -s http://localhost:8080/actuator/prometheus | findstr hikaricp

应看到:kafka_producer_record_send_total、hikaricp_connections_active、hikaricp_connections_pending 等。这些是排障时判断「是应用慢还是依赖慢」的关键线索。

讲清楚要点

  1. Actuator 是管理门面,所以生产必须限制暴露与鉴权——* 等于把内部状态大开,heapdump 可以拿到所有密钥和数据库密码。
  2. Micrometer 是指标引擎,所以业务代码依赖 MeterRegistry 而不是直接拼 Prometheus 文本——解耦后端格式,未来切 OTLP 也不动业务代码。
  3. 公共标签 application、region 利于聚合,所以要在配置层统一打——避免每个指标手写不一致,多副本环境下按标签 sum 聚合。
  4. 自动 HTTP 指标已覆盖入口,所以手动埋点应补充业务语义,而非重复每一个 controller——见 obs-instrumentation。
  5. health 影响流量与信任,所以指示器要真实——假 UP 比假 DOWN 更危险;liveness 和 readiness 要分开设计,依赖挂了只影响 readiness。
  6. scrape 与 OTLP 可并存,所以 Spring 指标出口要与整体遥测架构一致——见 obs-telemetry。
  7. 面板在 Grafana,所以命名与标签要稳定——对照 prom-grafana;改名等于断掉所有历史面板。

你可能会懵的地方

  • metrics 和 prometheus 端点有何不同? metrics 便于人工 JSON 查看,排障时 curl 一下看单个指标;Prometheus 拉取用 prometheus 文本格式,批量导出所有指标。数据源都是同一个 MeterRegistry,只是序列化格式不同。

  • 为何不能 include: *? 会暴露 env(环境变量,含数据库密码)、heapdump(堆 dump,含内存里所有对象)、beans(所有 Spring Bean)、mappings(所有 URL 映射)等敏感能力。攻击面和误操作面都放大,安全事件高发源。

  • health 细节对谁可见? 公网通常只给汇总 {"status":"UP"};细节(如 DB 连接数、磁盘剩余)when_authorized 或仅内网。K8s 探针只需要 200/503 状态码,不需要细节。

  • 和 prom-spring 课如何分工? 本课:Spring 应用侧暴露与埋点;那课:Prometheus 如何 scrape、怎么和 Grafana 配。一句话:本课「给信号」,那课「收信号」。

  • OTel agent 和 Micrometer 会冲突吗? 不冲突,分工不同:Micrometer 管 metrics(/actuator/prometheus),OTel agent 管 traces(OTLP → Jaeger)。日志的 traceId 由 OTel agent 注入 MDC。同一信号只允许一个生产者,别双计。

错法对照

错法问题正解
exposure.include: "*"暴露 env/heapdump 等敏感端点显式白名单 + 鉴权/网络隔离
health 永远 UP,忽略 DBK8s 探针认为健康,流量打到残废实例关键依赖纳入 readiness 指示器
liveness 和 readiness 不区分DB 抖动导致 K8s 反复重启容器liveness 只看 ping,readiness 看依赖
业务标签用 userId/submissionId时序爆炸拖垮 Prometheus低基数枚举;详情进日志和 Span 属性
只暴露指标,不做 traceId 关联排障时指标异常但无法定位具体请求日志/链路同步建设(见 obs-logs)
Actuator 端口暴露公网无防护攻击者直接访问管理端点内网、网关鉴权或 management 独立端口

卡点急救

  1. /actuator/prometheus 404:检查 micrometer-registry-prometheus 依赖是否在 classpath;检查 management.endpoints.web.exposure.include 是否包含 prometheus;检查 Spring Security 是否拦截了 /actuator/**。
  2. K8s 探针反复重启 Pod:先看 kubectl describe pod 里 liveness 和 readiness 的失败原因;再确认 liveness 是否误把 DB/Kafka 等依赖包含进去了——依赖挂了不该重启容器,只该摘流。
  3. 指标在 /actuator/prometheus 有,Prometheus 里没有:先查 Status → Targets 是否 UP;再查 Micrometer 导出名是否加了 _total 或 _seconds 后缀(如 judge_submissions_total 实际导出为 judge_submissions_total);最后确认 Prometheus scrape 配置的 metrics_path 是否为 /actuator/prometheus。

面试常问

  • Actuator 生产环境怎么配?安全底线是什么? 背这个版本:三底线——白名单暴露(只开 health/prometheus/metrics/info,禁止 *)、端口隔离(management 端口与业务端口分开,网络策略限制访问)、鉴权(Spring Security 保护或只允许内网 IP)。原因:heapdump 端点可以下载堆 dump 拿到所有密钥,env 端点泄露环境变量,beans 端点暴露内部结构。生产环境只暴露排障必需的最小集合。

  • Actuator health 的 liveness 和 readiness 怎么设计? 分工原则:liveness 只检查进程本身(ping),DB 挂了不该让 K8s 重启容器——重启解决不了 DB 问题,反而导致 cascading failure。readiness 检查所有关键依赖(DB、Redis、Kafka),任何一个挂了 K8s 摘流,防止请求打到一个「活着但已残废」的实例。判题系统例子:MySQL 挂了,liveness 仍 UP(进程活着),readiness DOWN(摘流),K8s 不再转发请求,等 MySQL 恢复后 readiness 自动 UP 重新接流量。

  • Micrometer 和 Prometheus 是什么关系? Micrometer 是 Java 应用的指标门面(类似 SLF4J 之于日志),提供统一的 MeterRegistry API;Prometheus 是后端时序数据库。Micrometer 通过 micrometer-registry-prometheus 把指标序列化成 Prometheus 文本格式,暴露 /actuator/prometheus 端点;Prometheus 定期 scrape 这个端点。好处:业务代码只依赖 Micrometer API,未来切 OTLP 或其他后端不动业务代码。

自测三问

  1. 生产 Actuator 暴露策略的三条底线是什么?为什么不能 include: *?
  2. curl /actuator/prometheus 成功后,Prometheus 端下一步要做什么配置?
  3. 判题 backend 的 liveness 和 readiness 指示器该怎么分组?MySQL 挂了应该影响哪个?

小结一句话

Actuator 是门面,Micrometer 是指标引擎——白名单暴露、真实 health、低基数埋点、liveness/readiness 分离,构成 Spring 侧可观测主路径。

延伸

  • Spring Boot Actuator 官方文档
  • Micrometer Prometheus Registry
  • Spring Boot Health Indicators
  • 下一课《SLO 与错误预算》:指标采齐了,怎么定义「对用户够好」并指导发布节奏。
加载本节练习…
← 上一课遥测与 OpenTelemetry下一课 →SLO 与错误预算