1. 先搞清楚Actuator到底解决了什么问题
1.1 没有Actuator时,我们是怎么做健康检查的
先把时间拨回到没有引入Actuator的时候。早期我维护过一个单体服务,运维同学为了监控服务是否存活,写了个Shell脚本每30秒curl一次首页,只要HTTP状态码是200就认为服务正常。这套方案在低并发时期勉强能用,但服务一旦进入高CPU、数据库连接池耗尽、磁盘写满的状态,首页依然能返回200——因为Tomcat线程还没完全卡死,有些请求路径根本不会触发数据库访问。
这种"假健康"状态非常坑人。负载均衡器以为节点正常,继续往里面分发流量,结果用户体验就是大量超时和5xx。后来我们引入了Spring Boot Actuator的健康检查端点,情况才彻底改善。
Actuator的核心价值可以归纳为三点:第一,提供标准化的健康检查入口,让K8s的liveness和readiness探针有准确的判断依据;第二,暴露运行时指标(JVM内存、线程、HTTP请求统计等),配合Prometheus这类监控系统做可视化;第三,提供info、env、beans、mappings等管理端点,让开发者在排查问题时不需要登录服务器抓thread dump和配置文件。
1.2 Actuator端点的两种暴露方式
用过Actuator的人都知道,它不是一个单独的端点,而是一组端点集合。每个端点都有自己独立的ID和路径,默认情况下路径是/actuator前缀加端点ID。比如健康检查端点就是/actuator/health,指标相关是/actuator/metrics,环境信息是/actuator/env。
Spring Boot 2.x里,端点默认只暴露health,其他端点全部隐藏。这个设计本身是出于安全考虑,但很多人第一次用的时候会奇怪为什么访问/actuator/info返回404。3.x也延续了这个策略。
端点的暴露方式有两种配置维度:一个是management.endpoints.web.exposure.include,控制哪些端点通过Web方式对外可见;另一个是management.endpoint.<id>.enabled,控制端点是否启用。这两者的关系是:先得enabled为true,才谈得上exposure。默认情况下所有端点都是enabled的,只是大部分没被expose。所以日常配置里,我们主要跟exposure打交道。
1.3 引入Actuator的成本和前提
引入Actuator本身非常轻,只需要在pom.xml或者build.gradle里加一个依赖:
如果你用的是Maven:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>如果是Gradle:
implementation 'org.springframework.boot:spring-boot-starter-actuator'有人会担心加了这个依赖会影响性能。实测下来,Actuator在默认状态下对业务接口的侵入几乎为零,影响可以忽略不计。它主要靠Spring的bean生命周期和事件机制收集信息,不是靠AOP拦截每个请求。只有在你主动开启了httptrace或者metrics的某些高频率指标后,才会有额外开销。这点我在后面指标采集部分还会细说。
2. 健康检查机制:从原理到生产配置
2.1 HealthIndicator的聚合原理
健康检查端点的核心不是简单的返回一个"UP"字符串,而是一个聚合多个健康指示器(HealthIndicator)的结果。Spring Boot内置了一堆自动配置的健康指示器,比如数据源(DataSourceHealthIndicator)、Redis(RedisHealthIndicator)、Elasticsearch、RabbitMQ、MongoDB等。
当你请求/actuator/health时,Actuator会遍历所有注册到上下文中的HealthIndicator,调用它们的health()方法,把返回结果统一聚合。聚合后的JSON结构大概是这样的:
{ "status": "UP", "components": { "db": { "status": "UP", "details": { "database": "H2", "validationQuery": "isValid()" } }, "redis": { "status": "UP", "details": { "version": "6.2.6" } } } }所有子组件的状态决定整体状态。默认规则是:任何一个子组件返回DOWN,整体状态就是DOWN;如果某些组件返回UNKNOWN或OFFLINE,整体状态会变成OUT_OF_SERVICE或UNKNOWN。这个聚合逻辑由HealthAggregator负责,默认实现是SimpleHealthAggregator,它按照状态优先级排序,DOWN优先级最高,其次是OUT_OF_SERVICE、UP、UNKNOWN。
这就是为什么很多人说Actuator的健康检查比"curl首页"可靠得多——它真的会去试着连一次数据库,调用一次Redis的PING命令,验证依赖组件是否真正可用。
2.2 自定义健康指示器:业务健康才是真的健康
内置的健康指示器只能覆盖框架层面的组件状态。对于业务系统来说,真正重要的往往是"核心业务链路是否可用"。举个例子,我之前做过一个报表服务,它的核心链路是:接收请求 → 查MySQL → 调外部数仓API → 生成文件。这三个环节任何一个挂掉,这个服务对外来说都是不健康的。
内置的DataSourceHealthIndicator只能告诉我MySQL是否可用,但它不知道外部数仓API是不是已经返回5xx了。这时就需要自定义HealthIndicator。
实现起来非常简洁,只需要实现HealthIndicator接口,重写health()方法:
@Component public class WarehouseApiHealthIndicator implements HealthIndicator { private final RestTemplate restTemplate; public WarehouseApiHealthIndicator(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @Override public Health health() { try { ResponseEntity<String> response = restTemplate.exchange( "https://warehouse.internal/api/ping", HttpMethod.GET, null, String.class ); if (response.getStatusCode().is2xxSuccessful()) { return Health.up() .withDetail("warehouseApi", "reachable") .withDetail("responseTime", response.getHeaders().getOrDefault("X-Response-Time", List.of("unknown"))) .build(); } return Health.down() .withDetail("warehouseApi", "unreachable") .withDetail("httpStatus", response.getStatusCode().value()) .build(); } catch (Exception e) { return Health.down(e) .withDetail("error", e.getMessage()) .build(); } } }这里有几个细节值得注意。第一,Health.up()和Health.down()返回的是Health.Builder,最终通过build()生成Health对象。第二,withDetail()可以带任意业务信息,这些信息会出现在健康检查响应里,排障时非常有价值。第三,catch住所有异常,不要让健康检查接口本身抛500,否则监控系统会收到错误的告警。
自定义HealthIndicator注册之后,不需要额外配置就会自动出现在/actuator/health的聚合结果里,因为这本质上就是一个Spring Bean,Actuator会自动收集容器中所有HealthIndicator类型的Bean。
2.3 readiness和liveness探针:K8s场景的必配项
如果服务部署在Kubernetes里,光有/actuator/health还不够。K8s区分了两种探针:readiness(就绪探针)和liveness(存活探针)。readiness决定Pod是否应该接收流量,liveness决定Pod是否应该被重启。
Spring Boot Actuator在2.2版本之后专门为这个场景引入了两组端点:/actuator/health/readiness和/actuator/health/liveness。它们把健康状态拆成了两个维度:
- readiness:应用是否准备好处理请求。启动过程中,Spring容器还没初始化完成时,readiness状态是DOWN;启动完成后自动变成UP。如果业务运行期间某个关键依赖不可用,readiness可以手动标记为DOWN,让K8s把流量摘掉。
- liveness:应用进程本身是否还活着。如果发生死锁、内存溢出等JVM级别的问题,liveness会让K8s重启Pod。
使用方式是在application.yml里配置:
management: endpoint: health: probes: enabled: true health: livenessState: enabled: true readinessState: enabled: true然后在K8s的Deployment配置中,这样配置探针:
livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 5 periodSeconds: 5这里我想强调一个大多数人会忽略的点:liveness探针的periodSeconds千万不要设置得太小,也不要让它依赖外部组件。因为如果外部数据库故障导致健康检查返回DOWN,liveness探针会不断失败,K8s会认为应用进程本身死了,进而杀掉Pod重启。这种情况下重启解决不了问题,反而可能造成所有副本同时重建,引发雪崩。正确的做法是:liveness探针只看进程级存活状态(用内置的liveness端点),readiness探针才用来反映业务依赖的健康情况。
2.4 健康检查的权限控制:details信息别乱公开
默认情况下,/actuator/health返回的JSON里包含components和details信息,比如数据库版本、Redis版本这些内部细节。这些信息虽然不算高度敏感,但不应该暴露给公网用户。
可以通过配置控制展示哪些信息:
management: endpoint: health: show-details: nevershow-details有三个可选值:never(不展示details)、when-authorized(当前用户有权限时才展示)、always(总是展示)。生产环境我推荐用never或者when-authorized。用when-authorized时,健康检查会走Spring Security的权限校验,只有登录用户才能看到details,未认证用户只能看到整体状态。
如果是给外部负载均衡器或者监控系统做探活,它们通常只关心HTTP状态码是200还是503,根本不需要details。把details关掉,既减小响应体积,又降低了信息泄露面。
3. 指标暴露:从内置Metrics到Prometheus对接
3.1 指标到底从哪里来
Actuator的metrics端点背后是Micrometer这个指标门面。Micrometer是Spring Boot 2.x默认引入的监控库,它做的事情可以理解为一个适配器层:你的应用里产生各种指标,Micrometer负责存储和暴露,至于暴露给谁(Prometheus、InfluxDB、Graphite),通过注册不同的MeterRegistry实现。
打开/actuator/metrics,你会看到当前JVM进程中所有可用的指标名列表,比如jvm.memory.used、jvm.threads.live、http.server.requests、system.cpu.usage、process.uptime等等。但有一个关键点:默认情况下,Spring Boot只把指标数据缓存在内存里,并不会主动推送给任何监控系统。你需要在pom里加对应的注册器依赖,Micrometer才会把指标暴露给对应的后端。
以Prometheus为例,加这个依赖:
<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>加了依赖之后,Actuator会自动新增一个端点/actuator/prometheus,这个端点以Prometheus文本格式输出所有指标。Prometheus服务端通过配置里加一个job定期拉取这个端点即可。
3.2 内置指标解读:排障时最常用的几个
在排障时,我几乎每次都会用这几个指标:
jvm.memory.used:已使用的堆内存。配合jvm.memory.max和jvm.memory.committed一起看,可以判断堆内存是否需要增加。committed表示JVM实际分配给堆的内存,如果committed一直在高位且接近max,说明堆比较紧张。
jvm.threads.live:当前存活线程数。线程数暴涨往往伴随着Tomcat线程池耗尽或者线程泄漏。如果这个数字在流量没有明显增长的情况下不断上升,基本可以断定有线程没有被正确回收。
http.server.requests:HTTP请求统计数据。这个指标自带tag,比如uri、method、status、exception。通过PromQL可以很方便地统计某个接口的P99耗时、错误率。
process.cpu.usage和system.cpu.usage:进程CPU使用率和系统CPU使用率。两者对比可以看出CPU是消耗在本进程上还是被其他进程抢占。
hikaricp.connections.active:如果用了HikariCP连接池,这个指标反映当前活跃连接数。配合hikaricp.connections.pending可以判断是否出现连接等待。
下面这张表是我在生产环境常用的指标和它们的含义:
| 指标名 | 含义 | 排障场景 |
|---|---|---|
| jvm.memory.used/committed/max | 堆内存使用/已分配/最大值 | 内存泄漏、堆大小设置不合理 |
| jvm.gc.pause | GC暂停时间及次数 | 频繁Full GC导致接口卡顿 |
| http.server.requests | 接口请求量、耗时、状态码分布 | 接口性能分析、错误率告警 |
| hikaricp.connections.active/pending | 连接池活跃连接和等待连接数 | 数据库连接池耗尽 |
| process.uptime | 进程运行时长 | 对比重启时间,排查"为什么又重启了" |
| system.cpu.usage / process.cpu.usage | 系统CPU/进程CPU使用率 | CPU负载过高时定位原因 |
3.3 自定义Metrics:给业务指标也加上监控
Actuator自带的指标大多是JVM和框架层面的,业务上的核心指标需要自己埋点。我举一个实际的例子。
我之前做一个订单服务,需要监控"订单支付超时未处理"的数量。这是一个很好的业务健康信号:如果这个数字持续增长,说明支付回调链路有问题。
用Micrometer自定义Counter非常简单:
@Component public class PaymentTimeoutMetrics { private final Counter paymentTimeoutCounter; public PaymentTimeoutMetrics(MeterRegistry registry) { this.paymentTimeoutCounter = Counter.builder("order.payment.timeout") .description("Number of orders that timed out waiting for payment") .tag("service", "order-service") .register(registry); } public void recordTimeout(String channel) { paymentTimeoutCounter.increment(); } }这里用Counter.builder()构建一个计数器指标,tag是标签,可以理解成指标的维度。之后在业务代码里调用recordTimeout()即可。
除了Counter,Micrometer还提供了Gauge(当前值)、Timer(耗时统计)、DistributionSummary(分布统计)。其中Gauge要特别注意,它不能自己增加或减少,只能设置一个当前值,通常用来度量队列长度、内存使用这类瞬时状态。
3.4 指标暴露的性能开销与控制
很多人在生产环境把所有端点全部暴露出来,结果发现内存占用涨了不少。原因在于Actuator会提前初始化所有Metrics的信息结构,并且如果打开了httptrace或者beans端点,每次请求都会积累追踪数据。
如果你不需要Metrics端点,可以通过配置关闭:
management: endpoints: web: exposure: include: health,info,prometheus只暴露health、info、prometheus三个端点即可。metrics端点本身的排障价值不大,Prometheus端点的数据量已经包含它了。这样一来,既保留了监控能力,又减小了Actuator本身的内存开销。
另外,/actuator/prometheus端点的拉取频率也不宜过高。Prometheus默认的scrape_interval如果是15秒,对绝大多数场景足够了。频繁拉取反而会加快指标缓存的重置频率,影响统计准确性。
4. 端点安全:最容易翻车的环节
4.1 默认暴露策略和常见误区
Spring Boot Actuator在2.x里默认只暴露health。听起来很安全对吧?但实际生产环境翻车最多的不是默认配置,而是"为了方便调试"随手把端点全部暴露了,然后没有加任何权限控制。
我见过不止一个团队,为了在联调环境看beans列表,直接在application.yml里写了:
management: endpoints: web: exposure: include: "*"结果这个配置一路被复制到了生产环境。/actuator/env可以把环境变量和配置项全部拉出来,包括数据库密码、Redis密码、第三方API的Secret。/actuator/heapdump可以直接下载一份JVM堆内存快照,里面可能包含敏感数据。这两个端点如果暴露到公网,基本等于把服务器密码贴在门口。
还有一种情况是只暴露了单个端点,但是用了Spring Security的permitAll放行,导致/actuator/health虽然在线,其他端点也因为没有鉴权而裸奔——Spring Security里如果你配了permitAll而没有区分路径,那是相当危险的。
4.2 利用Spring Security保护端点
生产环境中保护Actuator端点的最佳实践是走Spring Security统一鉴权。假设你的服务原本就用Spring Security做了登录认证,可以这样配置:
@Configuration @EnableWebSecurity public class ActuatorSecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/actuator/health/**").permitAll() .requestMatchers("/actuator/info").permitAll() .requestMatchers("/actuator/**").hasRole("ADMIN") .anyRequest().authenticated() ) .httpBasic(); return http.build(); } }这段配置的效果是:健康检查和info端点允许所有人访问,可以给负载均衡器和监控系统用;其余Actuator端点都需要登录,且必须具有ADMIN角色。
这里要提醒一个老生常谈但很重要的点:/actuator/health/**要写成通配符形式,因为K8s探针请求的是/actuator/health/readiness和/actuator/health/liveness,后面的子路径也要放行。只写/actuator/health会导致探针请求被拦下来,Pod一直进不了Ready状态,那种问题排查起来特别头疼。
4.3 独立管理端口:把运维入口和业务入口分开
如果服务同时承载业务流量和管理流量,最好的做法是把Actuator端点绑到一个独立的端口上,这样业务端口完全不受影响,管理端口的访问策略可以单独收紧。
配置方式:
management: server: port: 9090 address: 127.0.0.1这里把管理端口设置成9090,并且绑定在127.0.0.1。这意味着只有本机才能访问Actuator端点。监控系统如果是部署在同一台机器上,直接访问http://127.0.0.1:9090/actuator/prometheus即可;如果监控系统在远程,再用iptables或者K8s Service把9090端口映射出去,或者通过SSH隧道访问。
独立管理端口有个隐藏的好处:业务端口即使被大流量打满,管理端口的Tomcat连接器是独立的,健康检查依然可以正常响应。这一点在流量突增导致业务线程池打满时非常关键——不然K8s可能因为健康检查超时而误判Pod异常,频繁重启。
不过要记住,配置了独立管理端口后,原来的/actuator路径在业务端口上就不可用了,不能再通过8080/actuator/health访问了。很多人在切换端口后一时反应不过来,到处找404。
4.4 使用Token鉴权保护Prometheus端点
如果不想引入完整的Spring Security体系,只想给监控端点加一道简单的鉴权,可以用自定义Filter来实现。
以保护/actuator/prometheus为例,写一个OncePerRequestFilter:
@Component public class MetricsTokenFilter extends OncePerRequestFilter { private static final String TOKEN = System.getenv("METRICS_TOKEN"); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String path = request.getRequestURI(); if (!path.equals("/actuator/prometheus")) { filterChain.doFilter(request, response); return; } String token = request.getHeader("X-Metrics-Token"); if (TOKEN != null && TOKEN.equals(token)) { filterChain.doFilter(request, response); } else { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid metrics token"); } } }然后在Prometheus配置里加上这个Header:
scrape_configs: - job_name: 'my-spring-boot-app' metrics_path: '/actuator/prometheus' static_configs: - targets: ['192.168.1.10:8080'] authorization: credentials: 'your-metrics-token'这种方案的优点是轻量、无需引入Spring Security依赖,适合内部网络环境下使用。缺点也很明显:Token是静态的,泄露后只能改环境变量重启应用。比Spring Security的完整认证体系弱一些。对于一般内部监控场景,我认为够用了。
4.5 哪些端点绝对不能裸奔
总结一下哪些Actuator端点在生产环境绝不能被任何人随意访问:
env:能读取环境变量、配置文件中的全部值。Spring Boot会在响应里把propertySources里面的值列出来,其中就包括数据库账号密码、各种Secret。虽然某些敏感值会被脱敏显示(比如显示为******),但并不是所有配置都能正确脱敏,别赌这个。
heapdump:直接返回当前JVM堆的二进制快照。用MAT分析这个快照,能还原出内存中的对象、字符串常量、甚至包含在内存里的密码和Token。它比env更可怕,因为拿到手的数据是原始内存。
beans:虽然不直接泄露密码,但它完整列出了Spring容器里所有Bean的名称、类型、依赖关系。攻击者可以利用这些信息推断出内部实现细节,为后续攻击做准备。
conditions:展示了自动配置的匹配条件,包括哪些条件通过、哪些未通过。这个东西泄露了项目的依赖和配置结构,同样属于内部信息。
shutdown:默认禁用。如果被开启,攻击者可以优雅关闭应用。虽然它的实现要求POST请求,但配合CSRF绕过或者很简单的脚本就能利用。
以上这些端点,如果非要暴露,也必须放在独立管理端口、内网环境、或者完整鉴权体系的后面。任何情况下都不建议把include: "*"配到生产。
5. 实战:完整配置一个生产可用的Actuator
5.1 一个推荐的健康+监控配置模板
根据我的经验,下面这套Actuator配置适合大部分Spring Boot 2.x微服务。如果你的服务没有特殊需求,可以直接参考:
management: endpoints: web: exposure: include: health,info,prometheus base-path: /actuator endpoint: health: show-details: never probes: enabled: true health: livenessState: enabled: true readinessState: enabled: true metrics: tags: application: ${spring.application.name:unknown} server: port: 9090 address: 127.0.0.1这里有几个关键点我解释一下:
exposure.include只开了三个端点,杜绝了一大半安全风险。
show-details: never保证健康检查响应不含details信息。
probes.enabled: true和livenessState/readinessState配合,让K8s探针可以用独立的readiness/liveness路径。
metrics.tags.application给所有指标打上一个应用名标签,这样多个服务接入同一个Prometheus时,可以通过application标签区分不同服务的指标。
management.server.port和address把管理端口独立出来,并只绑定本机,避免直接暴露。
5.2 运行时动态查看指标:curl实战
配置好之后,我来演示几个常用的curl命令,这些命令在排查问题时会经常用到。
查看整体健康状态:
curl http://127.0.0.1:9090/actuator/health查看某个具体组件的健康状态,比如数据库:
curl http://127.0.0.1:9090/actuator/health/db注意这个路径要求show-details配置为when-authorized或always,否则看不到details。
列出所有指标名称:
curl http://127.0.0.1:9090/actuator/metrics查看指定指标的详细数据,比如JVM堆内存使用情况:
curl http://127.0.0.1:9090/actuator/metrics/jvm.memory.used查看Prometheus格式的全部指标:
curl http://127.0.0.1:9090/actuator/prometheus如果配了Token Filter,需要加上Header:
curl -H "X-Metrics-Token: your-token" http://127.0.0.1:9090/actuator/prometheus5.3 实战案例:通过Actuator定位数据库连接池耗尽问题
分享一个我印象比较深的排障案例。
当时一个订单服务的接口响应时间突然从50ms飙到3秒,而且流量并没有增长。我先看了/actuator/metrics/hikaricp.connections.active,发现活跃连接数一直维持在高位;再看了hikaricp.connections.pending,发现等待获取连接的请求数量在持续增长。这说明连接池被打满了。
接下来看http.server.requests指标,按uri和status分组,发现有个批量查询接口的耗时特别高,而且它的流量占比很大。进一步排查发现,这个接口里有个循环查询数据库的操作,每处理一条数据都要获取一次连接,循环几十次导致连接长时间占用。
最后定位到问题后,优化的方案是:把循环内的查询改成批量查询,将几十次的数据库往返合并成一次。优化后连接池的active数量立刻降下来了,接口的P99耗时恢复到100ms内。
这个案例想说明的是,Actuator的指标不是单纯让你看数字的,要结合业务链路去做归因分析。指标能告诉你"哪里不正常",但具体为什么不正常,还需要你把指标和代码逻辑串起来。
6. 常见问题与避坑要点
6.1 配置层面的坑
不知道为什么/actuator访问一直是404。先检查两件事:一是management.endpoints.web.exposure.include里有没有包含对应端点ID;二是访问路径对不对,Spring Boot 2.x的默认前缀是/actuator,3.x也一样。
include: "*"在YAML里要加引号吗?YAML语法里*是锚点符号,所以如果不加引号会被解析成别名引用,导致配置报错。安全写法是加引号,或者直接写include: health,info,prometheus这样的明确列表。
6.2 健康检查相关的坑
K8s readiness探针配好了,Pod却一直不Ready。原因多半是探针请求路径没配对,或者Spring Security拦截了/actuator/health/readiness。注意放行路径要写/actuator/health/**而不是/actuator/health。
服务启动了但健康检查一直返回DOWN。这种情况去/actuator/health的响应里看具体是哪个组件DOWN了。常见的有:DataSource连不上、Redis PING超时、或者自定义HealthIndicator抛了异常。
6.3 端点安全相关的坑
配置了独立管理端口后,原来的业务端口/actuator全没了。这是预期行为,Management端口变了之后,所有Actuator端点只在新的端口上提供服务。
只想给部分端点加鉴权,但又不想引入Spring Security。可以用自定义Filter,也可以用management.endpoint.<id>.enabled先关掉不需要的端点,把暴露面控制到最小。
6.4 指标相关的坑
加了micrometer-registry-prometheus依赖后/actuator/prometheus还是404。检查一下是不是用的Spring Boot 2.x,这个端点是在management.endpoints.web.exposure.include里加prometheus才生效的。如果用的是Spring Boot 3.x,路径和端点ID没有变化,但要注意3.x的一些依赖坐标有变化。
Prometheus拉取到的http.server.requests指标里有uri为/actuator/prometheus的数据。因为Prometheus拉取这个端点本身也是HTTP请求,也会被记入指标。这不算Bug,但做告警时要注意过滤掉这些管理端点的指标,否则可能产生误报。
6.5 排障经验杂谈
Actuator端点输出的信息是实时的,但/actuator/health并不记录历史状态,所以排查"几分钟前服务到底健不健康"这类问题时,还是得靠Prometheus这类监控系统存储历史数据。Actuator本身没有内置时间序列存储,不要指望它做历史回溯。
还有一个容易被忽略的点:Actuator的info端点可以通过application.properties或application.yml里的info.*前缀来填充自定义信息。比如:
info: app: name: order-service version: 1.2.3 description: Order management service配置后访问/actuator/info就能看到这些信息。这对多版本发布环境非常有用,可以快速确认当前节点跑的是哪个版本。
7. 我对Actuator实际使用的一些体会
用Actuator这几年,我最大的体会是:它的价值不仅在"监控",更在于"标准化"。以前每个团队自己做健康检查,有的用Shell脚本,有的写一个特殊的Controller,风格参差不齐。Actuator提供了一套统一的标准,无论谁接手都能立刻看懂服务状态。
第二个体会是"安全是配置出来的,不是默认的"。Spring Boot默认只暴露health确实很安全,但生产环境里因为图省事而把全部端点暴露出去的案例实在太多了。一套严格的端点暴露策略,加上独立管理端口,应该成为每个Spring Boot服务的标配。
第三个体会是"指标比日志更早发现问题"。日志是事后排查的手段,而指标可以在问题发生时就触发告警。熟练使用Actuator自带的指标,能让你在用户反馈之前就感知到异常。希望这篇文章能帮你把Actuator真正用起来,而不是只在引入依赖后看一眼/actuator/health的UP就完事。
最后分享一个小技巧:如果你们的监控系统还没搭建,可以先在本地用curl定时拉取/actuator/prometheus存成文件,再配合简单的脚本分析趋势曲线。这套极简方案能让Redis、MySQL、JVM的关键指标先跑起来,等后续引入Prometheus+Grafana时,配置几乎可以无缝迁移。毕竟Actuator的指标结构是标准化的,换监控后端根本不影响业务代码。