bigywater.tech
Spring · 79

健康检查:health 组、liveness 与 readiness 探针

/actuator/health 返回的 503 是怎么来的?数据库挂了 readiness 探针会变吗?liveness 和 readiness 差在哪?健康检查每次都会查数据库吗?这篇在 Spring Boot 4.0.8 上用自己写的指示器逐项实测。

200 / 503
业务检查 DOWN 时,默认配置下整体 /health 是 503,但 /health/readiness 仍是 200
5 次 → 1 次
连续请求 5 次健康检查,myCheck 执行 5 次;设 cache.time-to-live=10s 后只执行 1 次
2057 ms
两个各慢 1000 ms 的指示器,/actuator/health 的用时

默认有什么

实测 · 本机执行输出
    GET /actuator/health → 200 status=UP,components=['diskSpace', 'livenessState', 'myCheck', 'other', 'ping', 'readinessState', 'ssl'],groups=['liveness', 'readiness']
    GET /actuator/health/liveness → 200 status=UP
    GET /actuator/health/readiness → 200 status=UP
    GET /actuator/health/myCheck → 200 status=UP
    GET /actuator/health/nope → 404 
  /actuator/health 完整内容(去掉空白):{"components":{"diskSpace":{"details":{"total":494384795648,"free":73940172800,"threshold":10485760,"path":"/Users/w/Desktop/zen/tools/articles/jtmp/x79/.","exists":true},"status":"UP"},"livenessState":{"status":"UP"},"myCheck":{"details":{"note":"自定义检查"},"status":"UP"},"other":{"status":"UP"},"ping":{"status":"UP"},"readinessState":{"status":"UP"},"ssl":{"details":{"expiringChains":[],"invalidChains":[],"validChains":[]},"status":"UP"}},"groups":["liveness","readiness"],"status":"UP"}
  -- 设置 management.endpoint.health.probes.enabled=false:
    GET /actuator/health → 200 status=UP,components=['diskSpace', 'myCheck', 'other', 'ping', 'ssl']
    GET /actuator/health/liveness → 404 
  -- 设置环境变量 KUBERNETES_SERVICE_HOST=1.2.3.4(模拟「在 K8s 里」):
    GET /actuator/health → 200 status=UP,components=['diskSpace', 'livenessState', 'myCheck', 'other', 'ping', 'readinessState', 'ssl'],groups=['liveness', 'readiness']
    GET /actuator/health/liveness → 200 status=UP
    GET /actuator/health/readiness → 200 status=UP

liveness 和 readiness 默认开启,components 里有 diskSpace、ping、ssl 和两个 State。

状态聚合

实测 · 本机执行输出
  myCheck=UP             → /actuator/health 返回 HTTP 200,status=UP
  myCheck=DOWN           → /actuator/health 返回 HTTP 503,status=DOWN
  myCheck=OUT_OF_SERVICE → /actuator/health 返回 HTTP 503,status=OUT_OF_SERVICE
  myCheck=UNKNOWN        → /actuator/health 返回 HTTP 200,status=UP
  myCheck=MY_CUSTOM      → /actuator/health 返回 HTTP 200,status=UP
  -- 自定义映射 management.endpoint.health.status.http-mapping.DOWN=500、http-mapping.MY_CUSTOM=202,order=DOWN,MY_CUSTOM,UP:
  myCheck=DOWN       → HTTP 500,status=DOWN
  myCheck=MY_CUSTOM  → HTTP 202,status=MY_CUSTOM
  myCheck=UP         → HTTP 200,status=UP

DOWN 与 OUT_OF_SERVICE 返回 503;UNKNOWN 和未登记的自定义状态不会改变整体状态;可用 order 和 http-mapping 改。

探针组的成员

实测 · 本机执行输出
  myCheck=DOWN,默认配置:
    GET /actuator/health → 503 status=DOWN,components=['diskSpace', 'livenessState', 'myCheck', 'other', 'ping', 'readinessState', 'ssl'],groups=['liveness', 'readiness']
    GET /actuator/health/liveness → 200 status=UP
    GET /actuator/health/readiness → 200 status=UP
  myCheck=DOWN,management.endpoint.health.group.readiness.include=readinessState,myCheck:
    GET /actuator/health/liveness → 200 status=UP
    GET /actuator/health/readiness → 503 status=DOWN,components=['myCheck', 'readinessState']
    myCheck 改回 UP 之后:
    GET /actuator/health/readiness → 200 status=UP,components=['myCheck', 'readinessState']
  自定义分组 management.endpoint.health.group.custom.include=myCheck,other(show-details=never):
    GET /actuator/health → 200 status=UP,components=['diskSpace', 'livenessState', 'myCheck', 'other', 'ping', 'readinessState', 'ssl'],groups=['custom', 'liveness', 'readiness']
    GET /actuator/health/custom → 200 status=UP

默认探针组不含业务检查;要让 readiness 反映依赖,要显式 include;liveness 不要放外部依赖。

发布状态事件

实测 · 本机执行输出
  /ready?s=REFUSING_TRAFFIC → readiness→REFUSING_TRAFFIC
    GET /actuator/health/liveness → 200 {"status":"UP"}
    GET /actuator/health/readiness → 503 {"status":"OUT_OF_SERVICE"}
    GET /actuator/health → 503 {"components":{"diskSpace":{"details":{"total":494384795648,"free":73775214592,"threshold":10485760,"path":"/Users/w/Desktop/zen/tools/articles/jtmp/x79/.","exists":true}
  /live?s=BROKEN → liveness→BROKEN
    GET /actuator/health/liveness → 503 {"status":"DOWN"}
    GET /actuator/health/readiness → 503 {"status":"OUT_OF_SERVICE"}
    GET /actuator/health → 503 {"components":{"diskSpace":{"details":{"total":494384795648,"free":73775214592,"threshold":10485760,"path":"/Users/w/Desktop/zen/tools/articles/jtmp/x79/.","exists":true}

AvailabilityChangeEvent 可以让 readiness 返回 503 OUT_OF_SERVICE,让 liveness 返回 503 DOWN。

检查的代价

实测 · 本机执行输出
  默认:连续请求 /actuator/health 5 次,myCheck 被执行了 5 次
  management.endpoint.health.cache.time-to-live=10s:连续请求 5 次,myCheck 被执行了 1 次
  myCheck 和 other 各慢 1000 ms:GET /actuator/health 用时 2057 ms
  同时 GET /actuator/health/liveness 用时 4 ms

每次请求都执行检查,慢检查串行叠加,可用 cache.time-to-live 缓存。

分步演示

健康检查
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。被测应用是 spring-boot-starter-webmvc 加 spring-boot-starter-actuator 的单个程序,自己写了 myCheck 与 other 两个 HealthIndicator(状态与延迟可通过接口修改);暴露 health 并设置 show-details=always(只有第 3 节的自定义分组用 show-details=never);HTTP 请求用 Python http.client;「在 K8s 里」只是设置了环境变量 KUBERNETES_SERVICE_HOST,不是真的 K8s
    • 没有验证:真实 K8s 中 livenessProbe / readinessProbe / startupProbe 的配合与失败阈值(见 K8s 系列的探针一篇);数据库、Redis、消息队列等自带的健康指示器(这里只用了自己写的指示器);Spring Security 保护健康端点时的行为;show-details=when-authorized;响应式应用的 ReactiveHealthIndicator;health 端点的并发执行方式(这里观察到的是两个慢检查用时相加)
    京ICP备2026067502号-1京公网安备11010502063487号