通过自定义健康指标监视春季启动应用的健康
#java #springboot #kubernetes

免责声明

本文代表了我对该解决方案的看法,因此,任何建议,修复或讨论都将受到高度赞赏。

短篇小说

在当今复杂的软件景观中,了解应用程序的健康状况从未如此重要。应用程序的“健康”超出了正常运行时间。它涉及应用程序与其所依赖的外部资源有效交互的能力,例如数据库,API或缓存。

我们广泛使用Spring Boot应用程序,这些应用程序很大程度上取决于定制API,第三方API和内部caches等各种外部数据源。主要目的是确保这些应用程序在Kubernetes部署中的健康状况。

每个应用程序都有自己独特的健康状态,取决于其使用的外部资源的状态。例如,如果您的应用程序与第三方服务或数据库进行通信,则其健康状况不仅依赖于其内部功能,还依赖于这些外部系统的可用性和响应性。

如果必需的外部来源经历停机时间,即使应用程序本身运行完美,它也可能会严重影响我们的应用程序的性能和业务逻辑。因此,在确定应用程序的健康状况时要考虑这些外部因素至关重要。

健康检查为这一挑战提供了解决方案。它们允许您监视和评估您应用程序所依赖的系统的状态。如果外部来源对于您的应用程序很重要,则需要将其包括在健康检查中。

例如,如果您的应用程序在很大程度上依赖于特定的API,则应实现确保API启动并运行的健康检查。这样,如果有问题,您将被提醒,并且您可以及时解决它,以防止对您的申请产生任何严重后果。

Spring Boot的健康指标

Spring Boot提供了一个重要的功能,可以帮助您进行自定义的健康指标。 HealthIndicator接口提供了一种方法health(),可以返回健康响应。您可以根据应用程序的要求定义健康规则,范围从检查数据库连接到验证外部服务的状态。

使用Spring Boot,您可以根据自己的特定需求自定义这些健康指标,以确保应用程序健康状况的准确性。例如,如果您的应用程序使用外部API和一个缓存系统,则可以为API创建两个独立的健康指标,另一个用于缓存。如果两个系统遇到问题,相关的健康指标将报告,使您能够及时采取行动。

实施

让我们配置两种健康指标:

  1. 对于外部API
  2. 用于内部缓存

外部API的健康指标

我们的自定义ApiHealthIndicator接口为我们要通过提供doHealthCheck()方法来监视的所有外部API创建合同。默认情况下,我们将通过此接口的默认方法来创建健康状况:健康状态和一个不健康的状态。

您可以在down健康状态中添加其他详细信息,例如自定义运行时异常,详细消息等。

import org.springframework.boot.actuate.health.Health;
import reactor.core.publisher.Mono;

import static org.apache.commons.lang3.BooleanUtils.isFalse;
import static org.apache.commons.lang3.BooleanUtils.isTrue;

public interface ApiHealthIndicator {

    Mono<Health> doHealthCheck();

    default Health createHealth(Boolean status, String serviceName) {
        return isTrue(status)
                ? new Health.Builder().up().build()
                : createHealthDownStatus(status, serviceName);
    }

    default Health createHealthDownStatus(String serviceName) {
        var exception = new ServiceUnavailableException(String.format("The %s isn't available", serviceName));
        return new Health.Builder()
                .down(exception)
                .build();
    }

}

组件ServiceStateHealthIndicator有效地执行了所需的逻辑:它集成了从外部API检索当前状态的服务bean,表明API是否可用或不可用(true/false)。当监视资源(例如Kubernetes)通过执行器向应用程序的HealthEndpoint发送健康检查请求时,getHealth()方法会触发。此方法提供了所有HealthContributor实例的状态,其中包括我们的自定义ReactiveHealthIndicator

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class ServiceStateHealthIndicator implements ReactiveHealthIndicator, ApiHealthIndicator {

    private static final String SERVICE_NAME = "external-api";

    private final ApiService service;

    public ServiceStateHealthIndicator(ApiService service) {
        this.service = service;
    }

    @Override
    public Mono<Health> health() {
        return doHealthCheck()
                .onErrorResume(exception -> Mono.just(createHealthDownStatus(false, SERVICE_NAME)));
    }

    @Override
    public Mono<Health> doHealthCheck() {
        return service.getStatus()
                .map(status -> createHealth(status, SERVICE_NAME));
    }

}

当然,我们的自定义例外是解释其反映的状态:

public class ServiceUnavailableException extends RuntimeException {

    public ServiceUnavailableException(String message) {
        super(message);
    }

}

内部缓存的健康指标

假设我们应用程序的健康先决条件之一是存在内部缓存。如果缓存为空,我们希望防止应用程序完全启动。为了促进这一点,我们可以使用Spring Boot的ReadinessState.class来调整准备状态以控制可用性状态。

假设我们有一个接口CacheService,它提供了与我们内部缓存相关的每个类中实现的isNotEmpty()方法。此方法可提供直接的布尔结果,使我们能够验证我们的每个内部缓存是否处于有效状态。

通过注入包含所有缓存服务豆的地图,我们可以循环浏览每个缓存。如果即使是单个缓存为空,则准备状态会阻止任何流量到达应用程序。

我们可以在Spring引导中扩展AvailabilityStateHealthIndicator,以创建状态的映射并调整getState()方法。此方法基于我们的caches状态产生ReadinessState的实例。

当kubernetes等外部监视工具(例如,将HTTP请求发送到我们应用程序的准备就绪终点)时

import org.springframework.boot.actuate.availability.AvailabilityStateHealthIndicator;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.availability.ApplicationAvailability;
import org.springframework.boot.availability.AvailabilityState;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class CacheStateHealthIndicator extends AvailabilityStateHealthIndicator {

    private final Map<String, CacheService> cacheServices;

    public CacheStateHealthIndicator(Map<String, CacheService> cacheServices, ApplicationAvailability availability) {
        super(availability, ReadinessState.class, statusMappings -> {
            statusMappings.add(ReadinessState.ACCEPTING_TRAFFIC, Status.UP);
            statusMappings.add(ReadinessState.REFUSING_TRAFFIC, Status.OUT_OF_SERVICE);
        });
        this.cacheServices = cacheServices;
    }

    @Override
    protected AvailabilityState getState(ApplicationAvailability applicationAvailability) {
        boolean isEmpty = cacheServices.values()
                .stream()
                .map(CacheService::isNotEmpty)
                .toList()
                .contains(false);
        if (isEmpty) return ReadinessState.REFUSING_TRAFFIC;
        return ReadinessState.ACCEPTING_TRAFFIC;
    }

}

概括

总而言之,Spring Boot提供了一个全面且可自定义的系统,用于监视应用程序的健康状况。它的HealthIndicator接口使您可以考虑确定应用程序的健康状况时的所有关键因素,包括基本外部来源。此功能有助于防止小问题升级为重大问题,增强您的应用程序的可靠性。

在下一篇文章中,我将展示我们如何使用这些自定义的健康指标来实现application.properties文件中的kubernetes探针。

资源

  1. HealthIndicator
  2. Spring Boot health indicators
  3. ApplicationAvailability
  4. AvailabilityStateHealthIndicator