Предоставление настраиваемых компонентов группы работоспособности метрикам 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-компонент из ApplicationContext:

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

@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»