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中应用应是正常存活且可用的状态,不会重启,证明服务稳定性不受中间件影响。

相关推荐
追风少年浪子彦6 小时前
mapstruct与lombok冲突原因及解决方案
java·spring boot·spring·spring cloud
军军君016 小时前
基于Springboot+UniApp+Ai实现模拟面试小工具四:后端项目基础框架搭建下
spring boot·spring·面试·elementui·typescript·uni-app·mybatis
白仑色8 小时前
完整 Spring Boot + Vue 登录系统
vue.js·spring boot·后端
MZ_ZXD0018 小时前
flask校园学科竞赛管理系统-计算机毕业设计源码12876
java·spring boot·python·spring·django·flask·php
小郭的学习日记10 小时前
互联网大厂Java面试:从Spring Boot到微服务的场景应用
spring boot·微服务·java面试·技术栈·电商平台
超级小忍10 小时前
在 Spring Boot 中使用 MyBatis 的 XML 文件编写 SQL 语句详解
xml·spring boot·mybatis
Q_Q196328847511 小时前
python的平安驾校管理系统
开发语言·spring boot·python·django·flask·node.js·php
超级小忍11 小时前
在 Spring Boot 中如何使用 Assert 进行断言校验
spring boot·后端
程序猿小D11 小时前
[附源码+数据库+毕业论文+答辩PPT+部署教程+配套软件]基于SpringBoot+MyBatis+MySQL+Maven+Vue实现的交流互动管理系统
spring boot·mysql·vue·mybatis·毕业论文·答辩ppt·交流互动