资讯详情

资讯详情

Spring Boot Actuator实战:健康检查、指标监控与日志动态调整

项目上线以后最怕什么怕半夜手机突然响了群里有人喊“服务挂了”。更怕的是没人喊用户先发现了你才知道系统已经不可用了。很多团队的项目一上线就处于“裸奔”状态代码能跑就算成功但跑得好不好、内存紧不紧张、接口是不是变慢了一概不知。SpringBoot Actuator就是为了解决这个问题而生的它是Spring Boot自带的监控组件相当于给应用装了一套“体检设备”心跳、血压、血常规全都能实时看到。这篇文章就围绕Actuator的核心能力把健康检查、运行指标、日志动态调整这些关键玩法逐一拆开讲配合实际配置和源码级细节让你看完就能在自己的项目里用起来。适合正在做后端开发、微服务改造或者兼着运维活的同学也适合那些把项目扔上线就再也没管过的团队花半小时把这个组件吃透能省下后面无数个半夜排查的时间。1. 监控这件事先想明白再动手1.1 生产环境最怕的三种“无感知”做了几年后端之后你会发现生产环境最可怕的不是故障本身而是故障发生的时候你毫无感知。常见的有三种场景。第一种服务静默宕机。进程还在但线程池全部阻塞或者核心依赖断了接口一直超时外部负载均衡看TCP端口还通着流量继续往进打用户端已经卡成幻灯片。等你发现的时候故障可能已经持续了半小时。第二种内存缓慢泄漏。系统跑两三天没问题一周以后GC越来越频繁响应时间从50毫秒涨到2秒运维查了半天没找到原因只能重启先顶着。这个过程如果没有任何指标曲线你连“内存到底什么时候开始涨的”都说不清楚。第三种配置悄悄漂移。有人手动改过服务器环境变量或者配置中心的值被覆盖了但没有人同步更新文档所有排查方向都建立在错误的假设上。这些问题的共同点是缺少一扇“能观察到应用内部状态的窗口”。Actuator恰好就补上了这个缺口它不仅告诉你“进程还活着”还告诉你“活得好不好”“配置现在是什么”“线程在干什么”“内存在怎么变化”。它虽然解决不了所有监控问题但它是应用层监控里最基础、最顺手、几乎零成本的一层。1.2 Actuator在监控体系里的定位很多人一提到监控就想到各种全链路追踪和APM系统功能很强大但部署成本和学习成本都不低。而Actuator是Spring Boot框架自己带的标准组件只要你的项目是用Spring Boot写的加一个依赖就能用。它的定位是“应用内探针”解决的是进程级别的可观测性问题——我这个进程当前是什么状态内部各个模块是否正常JVM吃掉了多少内存日志级别能不能临时调一调它的数据从哪里来直接从Spring容器和应用的运行环境里来不需要额外埋点不需要改业务代码。对比一下就能理解APM系统更多关注跨服务的调用链、耗时分布、错误率是一张“整个系统的交通地图”而Actuator是每辆车自己的“仪表盘”告诉你发动机转速、水温、油量。两者不是替代关系Actuator是踩坑排查的第一站。接口慢了先看Actuator暴露的JVM指标和线程状态再决定要不要上全链路追踪去逐步排查这个顺序能提高排查效率。1.3 Actuator端点全景图Actuator的功能由一个一个的端点Endpoint组成每个端点提供一类监控信息。刚接触的时候没必要全记住先把核心的十几个搞清楚就行我整理了一个常用端点速查表。端点路径作用默认是否开启使用建议/actuator/health应用健康状态汇总是必用给负载均衡和运维监控做探活/actuator/info自定义应用信息是必用展示版本号、构建时间、描述信息/actuator/metrics运行指标列表总览否生产建议开启基础监控必需/actuator/metrics/{name}查看具体指标详情否按需使用排查JVM和HTTP指标时很关键/actuator/loggers日志配置查看与动态修改否强烈建议开启排障神器/actuator/env查看环境属性配置否慎用会暴露敏感信息需做访问控制/actuator/configprops查看ConfigurationProperties绑定情况否排查配置生效问题时好用/actuator/beans查看Spring容器中所有Bean否排查容器装配问题时使用/actuator/mappings查看URL路由与Controller映射否排查接口路径问题时使用/actuator/threaddump导出线程快照否CPU飙高、线程阻塞时必用/actuator/heapdump导出堆内存快照否OOM排查用注意文件体积可能很大/actuator/shutdown优雅关闭应用否默认禁用生产环境建议保持禁用这里要特别说一句端点默认只开启health和info其他都处于“能做但没暴露”的状态。这也是Spring官方刻意做的取舍——能力给你但默认保守防止把不该给的信息直接裸露在网络上。2. 核心端点拆解每个端点解决什么具体问题2.1 health健康状态的“红绿灯”health是用的最多的端点没有之一。它的原理并不复杂Spring Boot内置了一堆HealthContributor检查项自动对数据源、Redis、Elasticsearch、MongoDB等常见组件进行可用性探测最后把结果聚合到health端点里。返回的JSON长这样{ status: UP, components: { db: { status: UP, details: { database: MySQL, validationQuery: isValid() } }, diskSpace: { status: UP, details: { total: 536870912000, free: 322250637312, threshold: 10485760 } } } }状态值主要分为四档UP表示正常DOWN表示不可用OUT_OF_SERVICE表示主动下线UNKNOWN表示状态未知。负载均衡或者编排平台一般只认UP还是DOWN所以这个端点对服务上下线管理至关重要。有个细节很容易踩坑如果某个健康检查项挂了比如数据库连不上health端点会返回DOWN但应用进程本身还能处理请求吗答案是能。因为Spring Boot应用只要启动成功HTTP服务就一直开着健康状态跟进程状态是两回事。外部系统看到DOWN就把这个实例摘除流量了但如果你没有接入外部健康检查只是人肉去访问这个服务接口照样能返回数据前提是接口本身不依赖数据库。这个区别一定要理解健康检查不是“保活开关”它只是一个报告器真正的摘流量动作是外部系统根据这个报告做的。再看细节配置。默认情况下health端点不会显示具体的检查细节只会给你一个UP或DOWN避免泄露内部依赖信息。需要看细节就配置show-detailsmanagement: endpoint: health: show-details: always注意这个配置有三个可选值never不显示细节always始终显示when-authorized仅在已认证用户访问时显示。生产环境如果非要开细节建议用when-authorized配合Spring Security使用别直接裸奔。2.2 info让监控页面知道“这份代码是谁”info端点适合放一些静态的、不容易变化的信息比如应用名称、版本号、Git提交哈希、构建时间。团队里谁要是上线了不知道部署的是哪个版本看这个端点就一清二楚。配置方式最简单的是直接在application.yml里写info: app: name: user-service version: 1.4.2如果你用Maven构建还能在构建时自动生成构建信息。在pom.xml里加插件plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId executions execution goals goalbuild-info/goal /goals /execution /executions /plugin构建之后target目录下会多出一个META-INF/build-info.properties文件里面写好了构建时间和版本号。之后访问info端点就会自动带上这些内容。我做过的项目里还会把git的commit信息也接进来配一个git-commit-id-plugin插件一行配置就能实现对排查“这个故障是不是某次发布引入的”特别有用。2.3 metricsJVM和接口指标的核心入口metrics是目前Spring Boot监控里可玩性最高的端点。先看它暴露了哪些指标{ names: [ jvm.memory.used, jvm.memory.committed, jvm.gc.pause, jvm.threads.live, http.server.requests, system.cpu.usage, process.uptime ] }这些名字是Micrometer指标体系的基础指标每个指标都能通过/metrics/{name}查看详细数据。举个例子调整接口慢或者GC频繁时我第一个看的就是jvm.gc.pausecurl http://localhost:8080/actuator/metrics/jvm.gc.pause返回数据里能看到这个指标在不同标签比如gc区域下的次数、总和、最大值。如果GC暂停时间在持续上涨说明堆内存在稳定膨胀这时候再配合jvm.memory.used去确认哪块区域在涨基本就能判断是内存泄漏还是临时流量波动。还有一组指标值得关注就是http.server.requests。它统计了HTTP接口的请求次数、耗时、异常数量还能按URI和状态码拆开看排查某个接口是不是异常飙升非常直接。新版Spring Boot里它的命名和标签结构有调整不同版本之间会有差异实测Spring Boot 2.x和3.x在标签结构上就不完全一样切版本的时候要注意别按旧文档去写PromQL。2.4 loggers线上动态调日志级别的“后悔药”loggers端点是我认为最被低估的一个端点。它解决了一个经典问题线上报错了但日志级别是INFO看不到DEBUG级别的堆栈细节怎么办常规做法是改配置然后重启应用重启一次少说几十秒运气不好还要重新过一遍健康检查才能接流量。有了loggers端点直接发一个HTTP请求就能把某个类的日志级别改成DEBUG排查完再改回去全程不需要重启。查看某个包当前的日志级别curl http://localhost:8080/actuator/loggers/com.example.userservice动态设置日志级别curl -X POST http://localhost:8080/actuator/loggers/com.example.userservice \ -H Content-Type: application/json \ -d {configuredLevel: DEBUG}执行完以后这个包下面所有类的日志输出立刻变成DEBUG级别。注意这里有个坑动态设置后日志框架的配置其实是在线生效的但如果后续有人刷新了配置中心或者配置中心推送了一个新的logback配置可能会被覆盖回去。所以线上排查时改完不是结束要在日志里留下记录或者定个临时任务提醒自己改完后要复位。还有一个经验别一股脑把全局日志级别调成DEBUG。生产环境的QPS一大全量DEBUG日志会瞬间把磁盘打满应用直接卡死。我一般只调整出问题的那个业务包的日志级别精确到类更好。比如怀疑请求校验逻辑有问题就调com.example.userservice.controller.UserController这个类。2.5 env和configprops配置问题的“照妖镜”配置问题排查起来最头疼的点在于——你以为生效的配置和实际生效的配置可能根本不是一回事。可能是环境变量覆盖了配置文件可能是多个配置文件加载顺序有先后也可能是配置中心的值没有刷新到本地。env端点把这些“实际生效的值”一次性列出来。访问/actuator/env能看到所有配置来源包括系统环境变量、系统属性、application.yml里的内容还会标注每一项来自哪个property source。如果你怀疑数据库配置被覆盖了直接看env里spring.datasource.url这行是来自哪个配置文件优先级一目了然。configprops则展示所有ConfigurationProperties注解绑定的配置项比env看起来更结构化适合确认自定义的配置类到底绑上了没有、绑定成了什么值。两者配合起来大部分配置问题都能在五分钟内定位出来。但这里有一个严重的隐患env端点会把数据库密码、Redis密码等敏感信息全都显示出来。默认Actuator会把包含password、secret、key等关键字的字段值打码成******可这个过滤规则并不是百分之百可靠尤其是自定义配置项名称里写了password但没被默认规则捕获的情况。所以生产环境一定不要裸奔这个端点必须用Spring Security做保护。2.6 threaddump和heapdump故障现场的工具箱线程堆积、CPU飙高、死锁这类问题靠metrics只能看到现象要看根因就得抓现场。threaddump就是当前的Java线程快照里面包含每个线程的堆栈信息、锁状态、当前正在执行的方法。CPU占用最高的线程可以通过top命令找到线程号转成十六进制后和threaddump里的线程ID对上一眼就能定位到代码具体卡在哪一行。heapdump则是堆内存快照。应用出现OOM光看jvm.memory.used的曲线只能知道内存一直在涨如果要知道垃圾回收为什么没有回收、对象被谁引用了必须做堆转储并用工具分析。但heapdump有一个实际问题——文件体积非常大动辄好几个GB默认情况下直接用HTTP下载对生产环境影响很不友好。我的建议是生产环境不要随便触发heapdump优先抓threaddump和分析GC日志。真要做堆分析最好在压测环境复现问题再抓堆把对线上服务的影响降到最低。3. 从零实操搭一套最小可用的监控端点3.1 引入依赖与基础配置实操部分直接上代码。项目结构基于MavenSpring Boot版本以2.7.x和3.x都适用为例有版本差异的地方我会单独说明。pom.xml加入Actuator依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency如果你的应用本身就是Spring Boot项目这一步就完成了90%的工作。启动项目访问http://localhost:8080/actuator就能看到那个经典的端点列表JSON。注意一下Spring Boot 2.x和3.x的区别2.x里面端口路径默认是/actuator3.x延续了这个约定没有变化。但底层API和自动装配逻辑有一些调整比如3.x里面健康检查组的概念更完善配置前缀有些微调。我建议新项目直接用3.x老项目升级到3.x的时候别再照抄网上的旧配置跑一遍实测为准。3.2 配置暴露策略暴露要克制别全开默认情况下Actuator只把health和info暴露到Web端点metrics、loggers、env这些虽然都存在但你访问会发现404。要让它们可见需要手动配置management: endpoints: web: exposure: include: health,info,metrics,loggers这里我要多说一句网上很多教程喜欢用include: *把所有端点都暴露出来图省事这在生产环境是一个灾难性的配置。一旦这个应用暴露在公网允许访问的人可以直接通过env端点看到不少内部信息甚至能结合其他漏洞做进一步探测。正确的姿势是“最小暴露集”。基础监控开health、info、metrics这三个就够日常用了需要动态调日志的时候再加loggers排查容器装配问题的时候再临时加上beans、mappings其他按需打开用完再关。配置全部端点时也要记得用exclude排除掉shutdown。还有一个进阶配置如果公司内部网络隔离做得不好建议给监控端口单独分配一个server端口。这样业务端口对外监控端口只对运维网段开放management: server: port: 8081配置之后所有actuator请求都走8081端口跟业务8080端口互不干扰。这个做法对生产环境比较友好监控数据和业务流量隔离也方便在网关层单独控制访问规则。3.3 自定义健康检查让健康状态覆盖到核心依赖默认的健康检查项只能覆盖Spring Boot自动装配的组件比如数据源、Redis等。但实际业务里我们往往还依赖很多没有自动装配中间件的第三方服务比如某个内部REST接口、某个消息队列或者一个自研的本地缓存组件。这时候就要自定义HealthIndicator。实现方式很简单实现接口就行Component public class ExternalApiHealthIndicator implements HealthIndicator { private final RestTemplate restTemplate new RestTemplate(); Override public Health health() { try { ResponseEntityString response restTemplate.getForEntity( http://internal-service/health, String.class); if (response.getStatusCode().is2xxSuccessful()) { return Health.up() .withDetail(externalApi, available) .build(); } return Health.down() .withDetail(externalApi, unavailable, status response.getStatusCode()) .build(); } catch (Exception e) { return Health.down(e) .withDetail(externalApi, connect failed: e.getMessage()) .build(); } } }这个类一旦注册到Spring容器health端点的返回结构里就会自动多出一个externalApi的检查项。踩过的坑提醒两点。第一健康检查里别做重操作。每次探测都去发外部请求没错但超时时间一定要控制住我见过有人直接在健康检查里做数据库全表查询健康检查本身把数据库拖垮的案例。第二健康检查不要依赖业务数据完整性校验它的定位是“快而准”不是“全而细”。每个检查项耗时尽量控制在几百毫秒内。还有一个小技巧如果你的应用依赖特别多健康检查项的聚合逻辑想自己控制可以让自定义类实现CompositeHealthContributor接口自己组装多个检查项。这样做的好处是能自定义健康检查的整体结构但我个人建议先别过度设计默认的聚合方式已经足够应付大多数场景了。3.4 用Spring Security保护Actuator端点Actuator端点本身没有内置认证机制谁有网络通路谁就能访问。要加安全控制最常规的方案是Spring Security。这个方案有两种玩法。第一种所有Actuator端点都要求认证spring: security: user: name: admin password: 123456然后配置Security规则Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole(ADMIN) .requestMatchers(/actuator/health).permitAll() .anyRequest().authenticated(); } }第二种玩法比较实际。外部负载均衡或者Kubernetes的存活探针需要无账号就能访问health端点而其他端点必须认证。上面的配置已经体现了这个逻辑health放行其他走认证。注意Spring Boot 3.x里面WebSecurityConfigurerAdapter已经废弃了要基于SecurityFilterChain的写法Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(auth - auth .requestMatchers(EndpointRequest.to(health)).permitAll() .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole(ADMIN) .anyRequest().authenticated() ); return http.build(); }安全配置的实际落地还要根据公司统一认证体系来但思路是一致的区分探活和人工访问探活只放行health人工访问走统一认证。3.5 对接外部监控平台Prometheus指标导出的下一步Actuator自带监控指标但它的数据默认是不存储的只看实时数据意义有限。要从趋势上做分析和告警还是要对接专门的监控存储和展示平台。最常用的是Prometheus加Grafana这套组合。做法很简单引入Micrometer的Prometheus注册表dependency groupIdio.micrometer/groupId artifactIdmicrometer-registry-prometheus/artifactId /dependency配置里把prometheus端点加进暴露列表management: endpoints: web: exposure: include: health,info,metrics,prometheus重启之后访问/actuator/prometheus能看到Prometheus格式的指标文本。Prometheus服务器配置一个job定期去抓这个端点就行。Grafana里直接导入Spring Boot的官方仪表盘模板三分钟就能看到CPU、内存、GC、HTTP吞吐量这些基础图。这里有个特别容易掉坑的地方Prometheus抓取端点的频率通常默认15秒而metrics端点生成快照本身是有一定开销的。如果你的服务实例特别多并且每个实例都暴露Prometheus端点抓取压力也是要考虑的。按我看过的生产案例秒级抓取频率意义不大15到30秒的抓取足够了。4. 常见问题与排查技巧实录4.1 访问/actuator/health返回404怎么办这个问题的排查顺序基本固定。先确认依赖有没有引进去pom.xml里有没有spring-boot-starter-actuator。再确认配置里有没有exclude掉health有时候全局配置里写着include: *不够但exclude: health就会直接把health干掉。第三步看路径。Spring Boot 2.x的默认base-path就是/actuator如果你改过management.endpoints.web.base-path配置访问路径就会跟着变。第四步检查是不是在Web层被拦截了比如Spring Security或者网关做了路径过滤。还有一个容易忽视的点如果你的项目里用的是Spring MVC的旧版本路径规则可能访问/actuator/health不带斜杠结尾就不通实际报错会告诉你404。如果这几个都查完了还是404最后一步直接看启动日志。Spring Boot启动时会自动打印Actuator的端点映射信息里面会明确显示每个端点的路径和HTTP方法照着那个路径访问肯定没错。4.2 健康检查显示UP但服务实际不可用这是监控体系里最“阴”的问题因为误报比不报更可怕。你看着页面里大大的UP以为一切正常实际上业务已经跑不动了。我排查过的一个案例印象很深某服务的健康检查项只有数据库和磁盘空间但它的核心接口依赖一个内部Redis缓存Redis挂了以后接口一直报错health端点却纹丝不动地显示UP。原因很简单默认的健康检查体系根本没有覆盖Redis缓存因为那个Redis不是通过Spring Boot的标准自动配置引入的而是自己封装了一个客户端。解决方案就是前面说的把所有核心依赖全部通过自定义HealthIndicator加到健康检查里数据库、Redis、外部API、消息中心该查的都查。生产环境对健康检查覆盖度的要求就一条凡是核心请求链路里用到的外部依赖都必须出现在健康检查里。4.3 端点暴露太多导致的信息泄露风险这个问题非常容易被忽视。开发的机器上裸奔感觉不到问题等部署到服务器上如果安全组没做端口隔离外部就不难扫到。Actuator的env端点会把数据库连接串、用户名、密码某些情况下以明文形式暴露在JSON里。configprops会把这个应用的各种内部逻辑配置项翻个底朝天很多配置项能直接把系统的内部结构暴露给攻击者降低后续利用门槛。规避办法总结了三条第一生产环境暴露端点要克制只开必要的。第二用独立的management端口或者直接用Spring Security做认证。第三业务端口在云安全组层面就做好控制不允许随意访问非业务路径。做好了这三点Actuator信息泄露的问题基本就杜绝了。4.4 Actuator对性能有影响吗很多人一听到“监控”就觉得会拖慢系统其实正常用法下Actuator对业务请求的性能影响几乎可以忽略。它做的工作本质上是读取JVM和Spring容器已有的数据不需要额外埋点CPU和内存开销都非常小。真正有开销的是heapdump抓一次堆快照会触发STW生产环境滥用确实会让服务卡顿。还有一个隐性开销容易被忽视如果你暴露了metrics端点并且外部监控系统频繁轮询等于每个轮询周期都会触发一次指标快照的序列化。实例数少没关系实例数多的时候会有一些网络和序列化的压力。我建议抓取频率不要小于15秒同时可以用独立的management.server.port把监控流量跟业务流量隔离对性能的干扰会更小。4.5 版本差异Spring Boot 2.x和3.x的Actuator区别Spring Boot 3.x整体迁移到了Jakarta命名空间ActuatorAPI内部也做了一些重构。对使用者来说影响最大的变化一是Security配置方式不同二是部分端点返回的JSON结构有所调整比如metrics的标签组织方式、health里details和components的层级更清晰了。官方文档里有一张兼容性表升级的时候认真跑一遍测试用接口自动化把关键端点的返回结构断言一遍比自己人肉盯着看好使很多。还有一个实用建议别太依赖IDE自动提示和网上的老文章。每次升级大版本后直接运行起来访问一下/actuator看看实际返回了什么对照当前版本官方文档调整这是最可靠的路径。4.6 速查表常见问题与解决思路问题现象可能原因解决思路/actuator/health 404依赖未引入、端点被exclude、路径被网关或Security拦截按404排查四步走查看启动日志的端点映射health状态DOWN某个依赖不可达、自定义检查项抛异常看details里的组件状态逐项排查访问端点提示401/403有Security认证未登录或无权限检查账号权限或调整Security放行规则某些端点没有暴露默认只暴露health和info在include里显式添加需要的端点metrics指标始终为空版本差异或没有采集到样本某些指标延迟出现先访问总览确认names列表再按名字取详情动态改日志级别不生效日志框架不支持、日志配置被覆盖确认logback版本、检查配置来源优先级配合loggers配置精确到类5. 一些真实使用中的体会踩了几年坑我的最大感受是Actuator不是一个“装了就完事”的组件。很多人引入依赖看到端点列表就以为监控做好了但真正把监控做好的团队会持续维护健康检查的覆盖度、收敛暴露端点、把核心指标接到告警规则里。健康检查像一个正在值班的哨兵部署它不难但要让哨兵站对岗、看清敌情需要刻意设计和长期维护。最后分享一个我个人特别喜欢的小技巧把loggers端点做成一个内部服务接口配好权限出问题的时候直接POST一行HTTP请求就能秒开指定包的DEBUG日志定位完再发一个请求关掉。这个技巧帮我省了不知道多少次重启也避免了很多次深夜发布。如果你还没试过我建议下次线上出问题的时候先别急着重启进loggers端点开个DEBUG看看实际情况大概率会有惊喜。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →