В качестве вступления...
Промышленная эксплуатация требует знаний о том, как живет приложение. Этот тезис следует взять за аксиому. Таковыми знаниями являются метрики, производимые приложением. Метрики могут быть как чисто техническими (например, количество потребляемой ОЗУ) так и бизнесовыми (например, совершенные заказы).
Сам по себе срез метрик на текущий момент не всегда интересен и показателен. Встают базовые вопросы о сборе, хранении и отображении этих метрик.
Ситуация с потребностью в метриках и способе их обработки становится острее, когда используется сервисный подход и одно приложение, с точки зрения пользователя, поддерживается работой нескольких взаимодействующих сервисов. Добавив к этому облачное развертывание, пожнём жгучего перца.
О чем речь
Проект, на котором я участвую, как раз использует сервисы и развернут в AWS (Amazon Web Services). Основная масса сервисов построена с использованием Java 8+, Spring Boot и Docker. Доклад, прошедший на Luxoft IT Sreda #7 и данная статья выросли из нужд и задач проекта.
Моя цель рассмотреть практическую сторону сбора метрик приложения, использующего Spring Boot, и экспорт их в AWS CloudWatch. Это будет, по сути, step-by-step guide с пояснениями, разбором нюансов и возможных граблей.
Когда мы говорим о решении какой-то практической задачи, важно понимать ее симптоматику, чтобы сопоставить с имеющимся окружением. Возможно ли то, о чем идет речь применить один-в-один или требуется адаптация, дополнительные исследования.
Рассмотрим, из чего состоит наш сегодняшний контекст:
- Как данность, наше приложение или сервис основано на Spring Boot. В качестве сборщика Maven, Java 8+
- Docker. Однако, его использование не является критическим моментом. Важно, что для приложения, запущенного в docker все тоже будет работать
- AWS EC2 это наша инфраструктура, где запускается приложение. По своей сути это виртуальная машина в рамках AWS.
- AWS CloudWatch система мониторинга, являющаяся приборной панелью AWS-инфраструктуры.
Spring Boot
Перейдем к SpringBoot и его возможностям, которые могут нам помочь. Первое и самое важное, что есть в арсенале Actuator. Этот модуль дает возможность заглянуть внутрь работающего приложения и, до определенной степени, настроить его поведение. Например:
- Health check: информация о состоянии приложения в целом и его компонентов по отдельности
- Узнать настройки логирования и, при необходимости, скорректировать в runtime.
- Получить сведения о бинах, поднятых в контексте
- Считать метрики, производимые приложением, такие как: данные о памяти, процессорных ресурсам, поведению GC.
- ...
Как и многие компоненты Spring, Actuator похож на конструктор и может быть кастомизирован, расширен и настроен довольно тонко. Начать изучение можно отсюда.
Из всего набора нас, в данный момент, интересуют метрики. Actuator и метрики в частности, не только расширяем, но и преднастроен, поэтому только категорий метрик, доступных из коробки наберется пару десятков. Конечно же, есть возможность регистрация собственных метрик. Если в проекте подключен модуль web, метрики можно получит через обращение к
endpoint /metrics
.Сбор и предоставление метрик реализован через библиотеку micrometer, которая является продуктом компании Pivotal (ныне часть VMware), той же, что занимается разработкой Spring. micrometer позиционируется как вендорно-независимый фасад для экспорта метрик Java-приложений.
Для подключения actuator потребуется следующий starter:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency>
Spring Cloud
Далее нам потребуется модуль из Spring Cloud, а именно
spring-cloud-starter-aws
.У каждого модуля из семейства Spring Cloud свое версионирование и будет правильным использовать не конкретную версию модуля, а BOM
spring-cloud-dependencies
определенной версии (release
train), где собраны совместимые версии модулей. На момент написания
это Hoxton.RELEASE.Кроме вкусных автоконфигураций, для работы с AWS,
spring-cloud-starter-aws
, в качестве транзитивной
зависимости, дает aws-java-sdk
.В разделе dependencyManagement помещаем
<dependencyManagement>... <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies>...</dependencyManagement>
А в зависимости:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-aws</artifactId></dependency>
Micrometer registry
Теперь у нас есть micrometer в составе Spring Actuator и
aws-java-sdk
. Из коробки, micrometer не умеет
экспортировать данные в AWS CloudWatch, для этого требуется
соответствующая реализация MeterRegestry абстракции micrometer для
сбора метрик. По умолчанию подставляется SimpleMeterRegistry,
хранящий данные в памяти. Нужная реализация подключается вместе с
micrometer-registry-cloudwatch
. На момент написания,
актуальная версия 1.3.5.
<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-cloudwatch</artifactId> <version>1.3.5</version></dependency>
Итоговый pom.xml, в нашем случае, имеет следующий вид: github.com/MrArtemAA/blog-demos/blob/master/export-metrics-to-cloudwatch/pom.xml
app.properties
Перейдем к настройке свойств приложения, которые в нашем случае играют немаловажную роль:
1.
management.metrics.export.cloudwatch.namespace
:
нужно указать namespace, под которым в CloudWatch будут сохранятся
метрики. Т.к. в самой метрике нет информации от какого именно
инстанса приложения пришли данные, namespace как раз и будет
определять метрики конкретного инстанса. В противном случае, если
для нескольких инстансов определить один namespace, данные метрик
будут перемешаны и не понятно откуда какие пришли.2.
management.metrics.export.cloudwatch.batch-size
:
требуется явно установить значение свойства batch-size равным 20.
Что это за параметр и почему именно 20? Метрики посылаются клиентов
Amazon CloudWatch асинхронно, партиями (batch) по 20 (это
ограничение AWS) за раз.3.
cloud.aws.stack.auto=false
: нужно отключить
автоопределение
AWS CloudFormation стека, т.к. по умолчанию оно имеет значение
= true. Это свойство отвечает за то, будет ли приложение пытаться
автоматически получить название стека для конфигурации приложения
под облачное окружение (в парадигме infrastructure-as-code). При
развертывании на EC2, как на обычной виртуалке, этой информации
нет.Важно понимать, что всю информацию, которую AWS SDK будет пытаться получить самостоятельно без дополнительной конфигурации, она [библиотека] будет брать из метаданных EC2. Для получения этой информации есть специальный служебный endpoint, куда и происходит обращение.
Разбор полетов
batch-size
Еще раз вернемся к свойству
management.metrics.export.cloudwatch.batch-size
и
необходимости выставить его равным 20. Казалось бы, это все можно
сделать на уровне соответствующих библиотек, работающих с AWS.
Действительно, в micrometer-registry-cloudwatch
есть
интерфейс CloudWatchConfig с default
методом, который
корректно проверяет значение и кидает исключение при превышении 20.
Однако, если посмотреть
org.springframework.cloud.aws.autoconfigure.metrics.CloudWatchExportAutoConfiguration, увидим, что конфигурация происходит с помощью org.springframework.cloud.aws.autoconfigure.metrics.CloudWatchPropertiesConfigAdapter:@Bean@ConditionalOnMissingBeanpublic CloudWatchConfig cloudWatchConfig(CloudWatchProperties cloudWatchProperties) { return new CloudWatchPropertiesConfigAdapter(cloudWatchProperties);}
Адаптер, в свою очередь переопределяет batchSize() как
@Overridepublic int batchSize() { return get(CloudWatchProperties::getBatchSize, CloudWatchConfig.super::batchSize);}
Это значит, что если в
CloudWatchProperties
свойство
определено оно будет взято оттуда. Как раз в нем нет нужных
проверок и, если свойство не выставлено явно, значение по умолчанию
будет 10000.Запросы к AWS
Приложение (сервис) не может просто так делать запросы к сервисам Amazon. Они [запросы] должны содержать учетные данные. Для этого в AWS SDK есть цепочка провайдеров учетных данных, которую и рекомендуется использовать. Среди этих провайдеров есть Instance Profile, который как раз может получить данные на основе метаданных EC2. Чтобы это работало, необходимо убедиться, что к EC2 привязана роль.
Роль должна предоставлять права на выполнение запросов к CloudWatch и быть доступной для EC2. Роль можно указать как при создании нового EC2 instance, так и прикрепить к существующему. Применение роли происходит на лету.
Отключение метрик
Для локальной сборки или тестового окружения экспорт метрик может быть излишним. Установка свойства
management.metrics.export.cloudwatch.enabled=false
позволяет отключить экспорт метрик в CloudWatch, при этом сам сбор
метрик будет производится и, если у вас подключен модуль web, то по
endpoint /metrics
они все также будут доступны.Micrometer собирает и поставляет большое количество метрик. Если какие-то из них не нужны, их можно отключить. Можно отключать как индивидуально, так и целыми категориями. Так, например, свойство
management.metrics.enable.some.metric=false
,
отключит все метрики, чьи id будут начинаться с
some.metric
. Имейте ввиду: отключенные метрики не
будут собираться вообще.Запуск все AWS
Еще один сюрприз поджидает, если попытаться запустить приложение с минимально необходимыми настройками все AWS. Для работы необходимые данные региона, где работает приложение. Как мы уже знаем, все что не указано явно, AWS SDK будет пытаться получить из метаданных которых нет. Поэтому явно указываем нужный регион через свойство
cloud.aws.region.static=us-east-2
. Как и в случае с
названием стека (свойство cloud.aws.stack.auto
), имеет
место быть свойство cloud.aws.region.auto
равное
true
по умолчанию. Но просто выставление значения в
false нам не поможет, т.к. нужно именно значение региона.Также, как мы помним, запросы к AWS требуют учетных данных, поэтому если требуется передавать в CloudWatch метрики (или делать другие запросы к AWS), необходимо явным образом указать параметры для учетных данных через, например, свойства приложения или переменные окружения.
Передача через свойства приложения выглядит следующим образом:
cloud.aws.credentials.access-key=YOUR_ACCESS_KEY
cloud.aws.credentials.secret-key=YOUR_SECRET_KEY
Итоги
Как, я думаю, вы могли заметить, заставить работать всю схему и передавать метрики из приложения в CloudWatch не так сложно: потребовалось 3 зависимости и 3 свойства.
Самое важное как раз кроется в деталях. Библиотеки (фреймворки) такие, как Spring, AWS SDK, пытаются облегчить жизнь и максимально сделать всю работу за нас, но при этом любой шаг в сторону может привести к появлению stacktrace, попыткам понять, почему метрики никуда не идут, почему приложение вообще не запускается и как это все исправить. Раздел с разбором нюансов и описание некоторых деталей работы сервисов EC2 и CloudWatch, надеюсь, облегчат ваше понимание происходящего.
Если говорить об использовании самого CloudWatch, то, на мой взгляд, это достаточно естественный выбор при использовании инфраструктуры AWS.
Метрики это глаза и уши нашего приложения, однако это не отменяет того факта, что нужно понимать как метрики собираются, считаются и отображаются. Что за данные вы будете видеть на своих графиках. Особенно остро этот вопрос встанет при возникновении аномалий и разборе инцидентов. Если говорить о библиотеке micrometer стоит обратиться к документации, там, например, довольно подробно рассказано о типах измерителей (Meter).
Ссылки
Обмен опытом позволяет нам быстрее осваивать различные подходы инструменты, технологии и двигаться вперед. Поэтому не могу обойти стороной наиболее полезные материалы по теме, на которые не было ссылок по ходу статьи:
Spring Boot: Metrics With Micrometer and AWS CloudWatch
Spring Cloud. Using Amazon Web Services. Spring Boot auto-configuration
Spring in Action 5, Craig Walls, Manning
Популярно об Amazon Web Services
Готовый проект можно найти на GitHub.