Предоставление настраиваемых компонентов группы работоспособности метрикам Prometheus в Spring BootJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Предоставление настраиваемых компонентов группы работоспособности метрикам Prometheus в Spring Boot

Сообщение Anonymous »

У нас есть две специальные группы работоспособности: расширенная и готовность:
  • Код: Выделить всё

    extended
    : настраиваемые индикаторы HealthIndicator с большим количеством зависимостей, предоставляемые явно через свойство приложения
  • Код: Выделить всё

    readiness
    : все, кроме определенных в расширенной группе
В настоящее время при вызове конечной точки /actuator/health/readiness ответ выглядит следующим образом (упрощенно для удобства чтения):

Код: Выделить всё

db
├ storeDataSource
└ pizzaDataSource
diskSpace
gracefulShutdownHealthCheck
hazelcast
jms
├ internalActiveMQConnectionFactory
├ notifConnectionFactory
└ platformJmsConnectionFactory
ping
refreshScope
Мы хотим представить все компоненты из группы готовности как метрику Prometheus один за другим. Но поскольку эти компоненты не определены явно, а их количество можно увеличить/уменьшить путем добавления/удаления зависимостей Maven (например, jms или hazelcast), мы не знаем точный список имен компонентов во время компиляции.
Поэтому мы делаем следующее:

Код: Выделить всё

@Configuration
@AllArgsConstructor
public class HealthGroupMetricsConfig {

private final MeterRegistry meterRegistry;
private final HealthEndpoint healthEndpoint;

@PostConstruct
public void bindReadinessHealth() {
HealthComponent component = healthEndpoint.healthForPath("readiness");
CompositeHealth health = (CompositeHealth) component;

health.getComponents().forEach( (key, value) -> {
if (value instanceof Health h) {
Gauge.builder("app_health_readiness_component", h, he -> "UP".equalsIgnoreCase(h.getStatus().getCode()) ? 1 : 0)
.tag("component", key)
.register(meterRegistry);
} else if (value instanceof CompositeHealth ch) {
Gauge.builder("app_health_readiness_component", ch, he -> "UP".equalsIgnoreCase(ch.getStatus().getCode()) ? 1 : 0)
.tag("component", key)
.register(meterRegistry);
}
});
}

}
Но в этом случае метод healthForPath будет вызываться один раз во время @PostConstruct, и все компоненты будут зарегистрированы как метрика Prometheus статически, что означает, что каждый раз, когда вызывается конечная точка /actuator/prometheus, будут отвечать одни и те же состояния работоспособности (которые оценивались впервые), что нежелательно, поскольку нам нужны свежие данные каждый раз. время.
Если мы просто поместим healthForPath внутрь Gauge.builder, чтобы иметь новый вызов /actuator/health/readiness, то он будет вызываться несколько раз (столько, сколько компонентов у нас есть) без необходимости.
Наш второй подход заключался в том, чтобы вызвать healthForPath один раз в начале, чтобы просто собрать имена компонентов работоспособности, а затем внедрить их как bean-компонент из контекста приложения:

Код: Выделить всё

@Configuration
@AllArgsConstructor
public class HealthGroupMetricsConfig {

private final MeterRegistry meterRegistry;
private final HealthEndpoint healthEndpoint;
private final ApplicationContext applicationContext;

@PostConstruct
public void bindReadinessHealth() {
HealthComponent component = healthEndpoint.healthForPath("readiness");
CompositeHealth health = (CompositeHealth) component;

health.getComponents().keySet().forEach(name -> Gauge.builder("app_health_readiness_component", () -> {
HealthIndicator hi = applicationContext.getBean(name, HealthIndicator.class);
return hi.health().getStatus().equals(UP) ? 1 : 0;
})
.tag("component", name)
.register(meterRegistry));
}

}
Но оказалось, что не все компоненты являются HealthIndicator, и имя индикатора также не всегда совпадает с именем компонента здоровья. Перечислив все индикаторы HealthIndicator, мы получим следующее:

Код: Выделить всё

gracefulShutdownHealthCheck
hazelcastHealthContributor
diskSpaceHealthIndicator
pingHealthContributor
refreshScopeHealthIndicator
Как вы можете видеть, CompositeHealth (т. е. db и jms) отсутствуют, поскольку, например, notifConnectionFactory — это не HealthIndicator, а oracle.jms.AQjmsConnectionFactory.
Нашей последней мыслью было сделать вызов HTTP для каждого компонента, поскольку отдельные статусы можно оценить, вызвав /actuator/health/readiness/. Таким образом, мы можем достичь желаемой цели, но опасаемся некоторых проблем с производительностью из-за нескольких вызовов HTTP (если таковые имеются).
Есть предложения, как это сделать?
Мы используем Spring Boot версии 2.7.18.

Подробнее здесь: https://stackoverflow.com/questions/797 ... pring-boot
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»