Перейти к основному содержимому

Индикаторы работоспособности в Spring Boot

· 8 мин. чтения

1. Обзор

Spring Boot предоставляет несколько различных способов проверки состояния и работоспособности запущенного приложения и его компонентов. Среди этих подходов два наиболее заметных API HealthContributor и HealthIndicator .

В этом руководстве мы познакомимся с этими API, узнаем, как они работают, и посмотрим, как мы можем добавлять в них пользовательскую информацию.

2. Зависимости

Вкладчики информации о работоспособности являются частью исполнительного модуля Spring Boot , поэтому нам нужна соответствующая зависимость Maven :

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

3. Встроенные индикаторы здоровья

По умолчанию Spring Boot регистрирует множество `` HealthIndicator , чтобы сообщать о работоспособности определенного аспекта приложения .

Некоторые из этих индикаторов почти всегда регистрируются, например DiskSpaceHealthIndicator или PingHealthIndicator . Первый сообщает о текущем состоянии диска, а второй служит конечной точкой проверки связи для приложения.

С другой стороны, Spring Boot некоторые индикаторы прописывает условно . То есть, если некоторые зависимости находятся в пути к классам или выполняются некоторые другие условия, Spring Boot также может зарегистрировать несколько других HealthIndicator s. Например, если мы используем реляционные базы данных, Spring Boot регистрирует DataSourceHealthIndicator . Точно так же он зарегистрирует CassandraHealthIndicator , если мы будем использовать Cassandra в качестве хранилища данных.

Чтобы проверить состояние работоспособности приложения Spring Boot, мы можем вызвать конечную точку /actuator/health . Эта конечная точка сообщит об агрегированном результате всех зарегистрированных HealthIndicator s.

Кроме того, чтобы просмотреть отчет о работоспособности по одному конкретному индикатору, мы можем вызвать конечную точку /actuator/health/{name} . Например, вызов конечной точки /actuator/health/diskSpace вернет отчет о состоянии из DiskSpaceHealthIndicator :

{
"status": "UP",
"details": {
"total": 499963170816,
"free": 134414831616,
"threshold": 10485760,
"exists": true
}
}

4. Пользовательские индикаторы здоровья

В дополнение к встроенным, мы можем зарегистрировать пользовательские HealthIndicator , чтобы сообщать о работоспособности компонента или подсистемы. Для этого все, что нам нужно сделать, это зарегистрировать реализацию интерфейса HealthIndicator как компонент Spring .

Например, следующая реализация сообщает об ошибке случайным образом:

@Component
public class RandomHealthIndicator implements HealthIndicator {

@Override
public Health health() {
double chance = ThreadLocalRandom.current().nextDouble();
Health.Builder status = Health.up();
if (chance > 0.9) {
status = Health.down();
}
return status.build();
}
}

Согласно отчету о работоспособности этого индикатора, приложение должно работать только 90% времени. Здесь мы используем Health Builders, чтобы сообщать информацию о здоровье.

Однако в реактивных приложениях мы должны зарегистрировать bean-компонент типа ReactiveHealthIndicator . Реактивный метод health() возвращает Mono<Health> вместо простого Health . Кроме этого, другие детали одинаковы для обоих типов веб-приложений.

4.1. Название индикатора

Чтобы просмотреть отчет по этому конкретному индикатору, мы можем вызвать конечную точку /actuator/health/random . Например, вот как может выглядеть ответ API:

{"status": "UP"}

Случайный в URL - адресе /actuator/health/random является идентификатором этого индикатора. Идентификатор конкретной реализации HealthIndicator равен имени компонента без суффикса HealthIndicator . Поскольку имя компонента — randomHealthIdenticator , префикс random будет идентификатором.

С помощью этого алгоритма, если мы изменим имя компонента, скажем, на rand :

@Component("rand")
public class RandomHealthIndicator implements HealthIndicator {
// omitted
}

Тогда идентификатор индикатора будет rand вместо random .

4.2. Отключение индикатора

Чтобы отключить определенный индикатор, мы можем установить для свойства конфигурации management.health.<indicator_identifier > .enabled значение false . Например, если мы добавим следующее в наш application.properties :

management.health.random.enabled=false

Затем Spring Boot отключит RandomHealthIndicator . Чтобы активировать это свойство конфигурации, мы также должны добавить аннотацию @ConditionalOnEnabledHealthIndicator к индикатору:

@Component
@ConditionalOnEnabledHealthIndicator("random")
public class RandomHealthIndicator implements HealthIndicator {
// omitted
}

Теперь, если мы вызовем /actuator/health/random , Spring Boot вернет HTTP-ответ 404 Not Found:

@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(properties = "management.health.random.enabled=false")
class DisabledRandomHealthIndicatorIntegrationTest {

@Autowired
private MockMvc mockMvc;

@Test
void givenADisabledIndicator_whenSendingRequest_thenReturns404() throws Exception {
mockMvc.perform(get("/actuator/health/random"))
.andExpect(status().isNotFound());
}
}

Обратите внимание, что отключение встроенных или пользовательских индикаторов аналогично друг другу. Следовательно, мы можем применить ту же конфигурацию и к встроенным индикаторам.

4.3. дополнительные детали

В дополнение к отчету о статусе мы можем прикрепить дополнительные сведения о ключе-значении, используя withDetail(key, value) :

public Health health() {
double chance = ThreadLocalRandom.current().nextDouble();
Health.Builder status = Health.up();
if (chance > 0.9) {
status = Health.down();
}

return status
.withDetail("chance", chance)
.withDetail("strategy", "thread-local")
.build();
}

Здесь мы добавляем две части информации в отчет о состоянии. Кроме того, мы можем добиться того же, передав Map<String, Object> методу withDetails(map) :

Map<String, Object> details = new HashMap<>();
details.put("chance", chance);
details.put("strategy", "thread-local");

return status.withDetails(details).build();

Теперь, если мы вызовем /actuator/health/random , мы можем увидеть что-то вроде:

{
"status": "DOWN",
"details": {
"chance": 0.9883560157173152,
"strategy": "thread-local"
}
}

Мы также можем проверить это поведение с помощью автоматизированного теста:

mockMvc.perform(get("/actuator/health/random"))
.andExpect(jsonPath("$.status").exists())
.andExpect(jsonPath("$.details.strategy").value("thread-local"))
.andExpect(jsonPath("$.details.chance").exists());

Иногда возникает исключение при обмене данными с системным компонентом, таким как база данных или диск. Мы можем сообщить о таких исключениях, используя метод withException(ex) :

if (chance > 0.9) {
status.withException(new RuntimeException("Bad luck"));
}

Мы также можем передать исключение методу down(ex) , который мы видели ранее:

if (chance > 0.9) {
status = Health.down(new RuntimeException("Bad Luck"));
}

Теперь отчет о работоспособности будет содержать трассировку стека:

{
"status": "DOWN",
"details": {
"error": "java.lang.RuntimeException: Bad Luck",
"chance": 0.9603739107139401,
"strategy": "thread-local"
}
}

4.4. Детали Экспозиция

Свойство конфигурации management.endpoint.health.show-details управляет уровнем детализации, который может предоставлять каждая конечная точка работоспособности.

Например, если мы установим для этого свойства значение « всегда», то Spring Boot всегда будет возвращать поле сведений в отчете о работоспособности, как в приведенном выше примере.

С другой стороны, если мы установим для этого свойства значение never , то Spring Boot всегда будет опускать детали из вывода . Существует также значение when_authorized , которое предоставляет дополнительные сведения только для авторизованных пользователей. Пользователь авторизован тогда и только тогда, когда:

  • Она аутентифицирована
  • И она обладает ролями, указанными в свойстве конфигурации management.endpoint.health.roles .

4.5. Состояние здоровья

По умолчанию Spring Boot определяет четыре разных значения в качестве состояния работоспособности :

  • UP — компонент или подсистема работает должным образом
  • ВНИЗ — Компонент не работает
  • OUT_OF_SERVICE — компонент временно не работает
  • UNKNOWN — Состояние компонента неизвестно

Эти состояния объявляются как общедоступные статические конечные экземпляры вместо перечислений Java. Таким образом, можно определить наши собственные состояния работоспособности. Для этого мы можем использовать метод status(name) :

Health.Builder warning = Health.status("WARNING");

Состояние работоспособности влияет на код состояния HTTP конечной точки работоспособности . По умолчанию Spring Boot отображает состояния DOWN и OUT_OF_SERVICE , чтобы выдать код состояния 503. С другой стороны, UP и любые другие несопоставленные статусы будут преобразованы в код состояния 200 OK.

Чтобы настроить это сопоставление, мы можем установить для свойства конфигурации management.endpoint.health.status.http-mapping.<status> желаемый номер кода состояния HTTP:

management.endpoint.health.status.http-mapping.down=500
management.endpoint.health.status.http-mapping.out_of_service=503
management.endpoint.health.status.http-mapping.warning=500

Теперь Spring Boot сопоставит статус DOWN с 500, OUT_OF_SERVICE с 503 и WARNING с 500 кодами состояния HTTP:

mockMvc.perform(get("/actuator/health/warning"))
.andExpect(jsonPath("$.status").value("WARNING"))
.andExpect(status().isInternalServerError());

Точно так же мы можем зарегистрировать bean-компонент типа HttpCodeStatusMapper , чтобы настроить сопоставление кода состояния HTTP :

@Component
public class CustomStatusCodeMapper implements HttpCodeStatusMapper {

@Override
public int getStatusCode(Status status) {
if (status == Status.DOWN) {
return 500;
}

if (status == Status.OUT_OF_SERVICE) {
return 503;
}

if (status == Status.UNKNOWN) {
return 500;
}

return 200;
}
}

Метод getStatusCode(status) принимает состояние работоспособности в качестве входных данных и возвращает код состояния HTTP в качестве выходных данных. Кроме того, можно сопоставить пользовательские экземпляры состояния :

if (status.getCode().equals("WARNING")) {
return 500;
}

По умолчанию Spring Boot регистрирует простую реализацию этого интерфейса с сопоставлениями по умолчанию. SimpleHttpCodeStatusMapper также может считывать сопоставления из файлов конфигурации, как мы видели ранее.

5. Медицинская информация и показатели

Нетривиальные приложения обычно содержат несколько разных компонентов. Например, рассмотрим приложения Spring Boot, использующие Cassandra в качестве своей базы данных, Apache Kafka в качестве платформы публикации и подписки и Hazelcast в качестве сетки данных в памяти.

Мы должны использовать HealthIndicator , чтобы увидеть, может ли приложение взаимодействовать с этими компонентами или нет . Если канал связи выходит из строя или сам компонент не работает или работает медленно, то у нас есть неработоспособный компонент, о котором мы должны знать. Другими словами, эти индикаторы следует использовать для сообщения о работоспособности различных компонентов или подсистем.

Напротив, нам следует избегать использования HealthIndicator для измерения значений, подсчета событий или измерения длительности. Вот почему у нас есть метрики. Проще говоря, метрики — это лучший инструмент для создания отчетов об использовании ЦП, средней нагрузке, размере кучи, распределении ответов HTTP и т. д.

6. Заключение

В этом руководстве мы увидели, как добавить больше информации о работоспособности в конечные точки работоспособности привода. Кроме того, мы подробно рассмотрели различные компоненты в API-интерфейсах работоспособности, такие как Health , Status и статус отображения состояния HTTP.

В завершение мы быстро обсудили разницу между информацией о здоровье и показателями, а также узнали, когда использовать каждый из них.

Как обычно, все примеры доступны на GitHub .