Spring-Boot健康检查的正确打开方式

1-背景

1.1-概述

  • Spring项目健康检查地址应使用/actuator/health/readiness代替/actuator/health,以保证项目不因中间件的暂时不可用而重启;
  • 为保证k8s和非k8s环境的一致性,应通过Spring配置显示开启健康检查探针:management.endpoint.health.probes.enabled=true

1.2-问题

近期经常发生服务因健康检查失败而被重启的问题。

经排查,因nacos不稳定导致服务健康检查失败的情况比较常见,也偶有redis和数据库连接不稳定导致的健康检查失败导致的服务被重启。

1.3-根因

Spring框架的/actuator/health健康检查的整体状态,会因为任一健康检查子项不健康而不健康;

而nacos、redis、jdbc等子项的健康检查,会发起网络请求,会因为网络的不稳定等因素,出现健康检查失败的情况;

健康检查的本意,是保障服务的持续稳定性,而因为nacos这类非业务关键组件的健康检查失败导致服务被重启,反而得不偿失。

2-带病方案

2.1-修改内容

最直接的解决方案,是通过Spring配置关闭健康检查时的各子项,包括多种方法:

方法一:关闭指定项的健康检查项

yaml 复制代码
# bootstrap.yaml|application.yaml
management:
  health:
    # 关闭nacos配置中心健康检查
    nacos-config:
      enabled: false
    # 关闭nacos注册中心健康检查
    nacos-discovery:
      enabled: false
    # 关闭redis健康检查
    redis:
      enabled: false
    # 关闭jdbc数据源健康检查
    db:
      enabled: false
优点:
  1. 细粒度控制;
缺点:
  1. 每项依赖组件的健康检查都要明确指定,容易遗漏;

方法二:排除指定健康检查项的AutoConfiguration

yaml 复制代码
# bootstrap.yaml|application.yaml
spring:
  autoconfigure:
    exclude:
      # 排除nacos配置中心健康检查的自动配置
      - com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration
      # 排除nacos注册中心健康检查的自动配置
      - com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration
      # 排除redis健康检查的自动配置
      - org.springframework.boot.actuate.autoconfigure.data.redis.RedisHealthContributorAutoConfiguration
      - org.springframework.boot.actuate.autoconfigure.data.redis.RedisReactiveHealthContributorAutoConfiguration
      # 排除jdbc数据源健康检查的自动配置
      - org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthContributorAutoConfiguration
优点:
  1. 细粒度控制;
  2. 更彻底、更明确地排除自动装配类;
缺点:
  1. 每项依赖组件的健康检查都要明确指定,容易遗漏;

方法三:默认关闭所有Spring健康检查子项

yaml 复制代码
# bootstrap.yaml|application.yaml
management:
  health:
    # 所有健康检查子项默认关闭,可单项打开
    defaults:
      enabled: false
优点:
  1. 全局开关,减少配置量、避免遗漏;
  2. 兼顾细粒度配置,可有选择性打开部分健康检查子项;
缺点:
  1. 失去了对中间件是否可用状态的可观测性。

2.2-总结

所有方案都是关闭/actuator/health子项的健康检查,共同缺点是:

  1. 中间件是否可用的可观测性与服务可用性不可兼得;
  2. 需要细粒度配置。

3-进阶方案

查询Spring官方文档,发现Spring早就提供了对k8s专用的健康检查API,可以兼顾中间件的可观测性与服务可用性:

参见:《Kubernetes Probes

3.1-修改内容

要使用Spring的这种能力,只需两步:

步骤1:打开k8s专用健康检查端点

Spring会自动检查是否处于k8s环境中、并按需启动存活和可读健康检查端点。为了本地、开发、生产的一致性,我们可以通过开关显示打开:

yaml 复制代码
# bootstrap.yaml|application.yaml
management:
  endpoint:
    health:
      # 显示开启存活和可读探针
      probes:
        enabled: true

步骤2:替换健康k8s健康检查地址

修改部署模板中健康检查的配置:

yaml 复制代码
# deployment.yaml
livenessProbe:
  httpGet:
    path: "/actuator/health/liveness"
    port: 8080
  failureThreshold: ...
  periodSeconds: ...
readinessProbe:
  httpGet:
    path: "/actuator/health/readiness"
    port: 8080
  failureThreshold: ...
  periodSeconds: ...

3.2-检查效果

步骤1:检查存活和可读端点是否启用

本地启动服务之后,可以通过/actuator/health是否包含了存活和可读健康检查子项:

请求
shell 复制代码
curl http://localhost:8080/actuator/health
响应内容
json 复制代码
{
  "status": "UP",
  "groups": [
    "liveness",
    "readiness"
  ],
  "components": {
    ...
    "livenessState": {
      "status": "UP"
    },
    "readinessState": {
      "status": "UP"
    }
  }
  ...
}

步骤2:检查k8s的健康检查配置是否生效

应用部署后,可以k8s的yaml配置检查健康检查是否生效。

健康检查地址应该由/actuator/health被修改为了/actuator/health/readiness

yaml 复制代码
livenessProbe:
  httpGet:
    path: "/actuator/health/liveness"
    port: 8080
  failureThreshold: ...
  periodSeconds: ...
readinessProbe:
  httpGet:
    path: "/actuator/health/readiness"
    port: 8080
  failureThreshold: ...
  periodSeconds: ...

步骤3:验证中间件不可用时服务的健康状态

通过配置错误的地址等方法,让某中间件(如redis)不可用:

yaml 复制代码
# bootstrap.yaml|application.yaml
spring:
  data:
    redis:
      host: error
      port: 1234
      ...

重启服务使配置生效。

1.健康检查根路径为失败状态

发送请求:

shell 复制代码
curl http://localhost:8080/actuator/health

响应结果:

json 复制代码
{
    "status": "DOWN",
    "groups": [
        "liveness",
        "readiness"
    ],
    "components": {
        "livenessState": {
            "status": "UP"
        },
        "nacosConfig": {
            "status": "UP"
        },
        "ping": {
            "status": "UP"
        },
        "readinessState": {
            "status": "UP"
        },
        "redis": {
            "status": "DOWN",
            "details": {
                "error": "org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis"
            }
        }
    }
}
2.存活探针应为成功状态

发送请求:

shell 复制代码
curl http://localhost:8080/actuator/health/liveness

响应结果:

json 复制代码
{
    "status": "UP"
}
3.可读探针应为成功状态

发送请求:

shell 复制代码
curl http://localhost:8080/actuator/health/readiness

响应结果:

json 复制代码
{
    "status": "UP"
}

小结

此时k8s中应用应是正常存活且可用的状态,不会重启,证明服务稳定性不受中间件影响。

相关推荐
CodeUp.1 小时前
基于SpringBoot的OA办公系统的设计与实现
spring boot·后端·mybatis
小醉你真好1 小时前
Spring Boot + ShardingSphere 分库分表实战
java·spring boot·后端·mysql
战族狼魂4 小时前
通过 Flink 和 CDC 从 Oracle 数据库获取增量数据,并将这些增量数据同步到 MySQL 数据库中
java·数据库·spring boot·mysql·oracle·flink
it自4 小时前
SpringMVC在前后端分离架构中的执行流程详解
java·spring boot·后端·spring·架构
创码小奇客5 小时前
从 0 到 1 落地 SpringBoot+RocketMQ:架构师亲授分布式通信最优解
spring boot·rocketmq·trae
小醉你真好5 小时前
Spring Boot + ShardingSphere 实现分库分表 + 读写分离实战
spring boot·后端·mysql
斜月6 小时前
Spring 自动装配原理即IOC创建流程
spring boot·后端·spring
半部论语7 小时前
Spring **${}** vs **#{}** 语法全景图
java·数据库·spring boot·后端·spring
麦兜*7 小时前
Spring Integration 整合 Web3.0网关:智能合约事件监听与Spring Integration方案
java·spring boot·后端·spring·spring cloud·web3·智能合约
日月星辰Ace7 小时前
🚀 从压测到优化:用 k6 和 SpringBoot 构建高性能系统(附实战案例)
spring boot·后端·性能优化