Что и почему мониторинга

Часто, когда мы начинаем создавать сервисы, отслеживание того, насколько хорошо эти сервисы работают, оказывается ниже в нашем списке приоритетов. Часто мы, как разработчики, склонны думать «как мне заставить это работать», а иногда забываем спросить «как только это заработает, как мне измерить производительность и работоспособность моего сервиса?» Однако этот вопрос почти так же важен, как и то, как заставить ваш код работать в первую очередь.

Когда клиенты начинают обращаться к вам с проблемами, которые говорят, что ваша платформа не работает или они не смогли разместить заказ на вашем веб-сайте, как вы отследите первопричину проблемы? Или, когда вам нужно доказать, что система, которую вы строили месяцами, прибыльна, как вы собираетесь доказать это заинтересованным сторонам? Здесь, в I Love My Local Farmer, мы должны иметь возможность быстро ответить на эти вопросы, чтобы гарантировать, что наши услуги - и, следовательно, наш бизнес - работают продуктивно.

Для этого нам необходимо создать легко усваиваемые информационные панели, которые наши операционные группы могут использовать для диагностики проблем или предоставления операционных показателей. К счастью, на рынке, а также в AWS есть множество сервисов, которые позволяют нам настраивать такие операционные индикаторы, и мы можем легко создавать их в тандеме с нашей сервисной инфраструктурой с помощью Cloud Development Kit (CDK). Дополнительную информацию о нашем сервисе и о том, как мы настроили его в CDK, можно найти в других наших публикациях, посвященных архитектуре сервиса и использованию CDK в Java.

В этой статье я сначала покажу, как генерировать пользовательские метрики для ваших лямбда-выражений, а затем подробно расскажу, как использовать CDK для создания информационных панелей и сигналов тревоги, которые могут помочь вам быстро выявить проблемы в вашем сервисе. Поскольку мы только начинаем настраивать наблюдаемость для наших услуг здесь, в I Love My Local Farmer, в этой статье мы сосредоточимся только на том, «как» настраивать показатели и информационные панели. Мы рассмотрим « какие метрики вам следует установить в следующих публикациях, когда мы узнаем больше о сервисе. А пока мы хотели рассказать о настройке некоторых начальных индикаторов и о том, как сделать их легко доступными для наших операционных групп.

Мы начнем с рассмотрения организации показателей в AWS (I). Затем мы перейдем к тому, как генерировать пользовательские метрики из ваших лямбда-выражений Java с помощью встроенного формата метрик (II). После этого мы увидим, как создавать информационные панели на основе этих показателей (III), а также как настраивать будильники и уведомления, чтобы вы знали, когда их проверять (IV). В этой статье мы будем использовать множество примеров из нашей собственной службы Delivery API. Если в какой-то момент вы захотите углубиться в код, его можно найти в нашем репозитории Github здесь.

Заявление об ограничении ответственности
I Love My Local Farmer - это вымышленная компания, вдохновленная взаимодействием клиентов с архитекторами решений AWS. Любые истории, рассказанные в этом блоге, не относятся к конкретному клиенту. Сходства с любыми реальными компаниями, людьми или ситуациями чисто случайны. Истории в этом блоге отражают точку зрения авторов и не одобрены AWS.

I. Метрики в AWS

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

К счастью, в AWS это сделать намного проще, потому что почти все сервисы выдают метрики, которые указывают как на их производительность, так и на работоспособность. В нашем случае у нас есть API, настроенный с использованием API Gateway, который интегрируется с Java Lambdas для отслеживания наших доставок. Удобная функция как API Gateway, так и Lambdas заключается в том, что они генерируют метрики, которые позволят вам отслеживать определенные свойства вашей службы. По умолчанию они включают в себя такие вещи, как количество различных HTTP-ответов, возвращаемых вашим API, и количество вызовов ваших лямбда-выражений. Кроме того, вы можете создавать собственные метрики в своих лямбдах, чтобы отслеживать любое количество вещей, которые вам нужно отслеживать в своей системе.

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

Основные концепции Cloudwatch

Прежде чем мы углубимся в настройку показателей и панелей мониторинга, важно понять, как эти метрики организованы в сервисе наблюдения AWS Cloudwatch. Для этого нам нужно знать три важных понятия - пространства имен, измерения и, наконец, сами показатели. Пространство имен - это группа показателей, которая позволяет их упорядочивать в соответствии с их услугами, а измерение - это логический способ группировки показателей, которые имеют что-то общее, например метрики, относящиеся к одной и той же лямбда-функции. Наконец, метрики - это фактические точки данных, которые генерируются и сгруппированы в соответствии с их пространством имен и размерами.

У каждого сервиса AWS, такого как Lambda или API Gateway, есть собственное пространство имен, и если вы откроете консоль Cloudwatch Metrics, вы увидите его для всех используемых вами сервисов, которые в настоящее время генерируют метрики. Все они имеют префикс AWS/ при программном указании, что важно помнить на будущее, когда мы будем обсуждать их добавление в информационные панели, поскольку этот префикс не отображается в консоли. Пространства имен предоставляют нам как разработчикам способ организовать наши различные службы, чтобы мы могли быстро находить показатели, которые наиболее актуальны для любых проблем, которые мы можем исследовать. По умолчанию все ваши метрики EMF будут помещены в пространство имен aws-embedded-metrics. Чтобы улучшить читаемость, вам нужно переопределить это, вызвав MetricsLogger.setNamespace() в своем коде. Например, на изображении ниже для некоторых показателей было изменено пространство имен на DeliveryApi, чтобы соответствовать нашему сервису. Разные пространства имен можно использовать в том случае, если у вас есть отдельные микросервисы, размещенные в AWS в одной и той же учетной записи, и вы хотите быстро перейти к метрикам для конкретной из них, не просматривая все настраиваемые метрики в учетной записи.

В пространстве имен также есть группы, называемые измерениями. Параметр можно рассматривать как ярлык для показателя. С каждым создаваемым показателем может быть связано до 10 измерений, и этот «набор параметров» образует уникальный идентификатор для показателя. По сути, это способы пометить ваши метрики, чтобы вы могли создать несколько метрик с одним и тем же именем. Например, в нашем сервисе у нас есть несколько лямбда-функций, которые все подключаются к одной и той же базе данных. Мы хотели создать метрику «SQLExceptions» для каждой функции, поэтому мы добавили имя функции как измерение метрик, генерируемых каждой лямбда-функцией. Измерения - важное понятие в Cloudwatch, потому что они составляют часть идентичности метрики. Таким образом, если вы хотите отображать свои показатели на панели управления или установить для них сигнал тревоги, вам необходимо знать точный набор параметров для конкретной метрики.

II. Использование формата встроенных показателей (EMF) в лямбдах Java

Теперь, когда мы знаем, как организованы метрики, мы можем начать создавать свои собственные. К счастью, AWS предоставляет удобный способ получения метрик из ваших лямбда-выражений, который называется формат встроенных метрик. Формат встроенных метрик, или EMF, представляет собой стандарт журналов в формате JSON, реализованный AWS, который позволяет печатать операторы журналов непосредственно на консоли и записывать их как метрики в Cloudwatch. Это замечательно, потому что это означает, что вам не нужно делать какие-либо дополнительные вызовы API к другим службам из ваших лямбда-выражений, вы можете просто писать журналы, которые автоматически обрабатываются как метрики.

Хотя можно самостоятельно отформатировать журналы во встроенном формате метрик, AWS предоставляет библиотеки, упрощающие этот процесс. В Java есть удобная библиотека aws-embedded-metrics-format, которая предоставляет оболочки, так что вам не нужно форматировать JSON вручную. Вместо этого вы просто создаете экземпляр MetricsLogger и используете встроенные функции для организации и выдачи ваших показателей. Ниже приведен пример со страницы Github, показывающий все необходимое для создания пользовательской метрики в функции Java Lambda.

import software.amazon.cloudwatchlogs.emf.logger.MetricsLogger;
import software.amazon.cloudwatchlogs.emf.model.DimensionSet;
import software.amazon.cloudwatchlogs.emf.model.Unit;
class Example {
    public static void main(String[] args) {
        MetricsLogger metrics = new MetricsLogger();
        metrics.putDimensions(DimensionSet.of("Service", "Aggregator"));
        metrics.putMetric("ProcessingLatency", 100, Unit.MILLISECONDS);
        metrics.putProperty("RequestId", "422b1569-16f6-4a03-b8f0-fe3fd9b100f8");
        metrics.flush();
    }
}

Обратите особое внимание на .flush() в конце примера. Без него ваша функция никогда не распечатает какие-либо показатели, и по опыту очень сложно понять, почему вы не видите их в журналах Cloudwatch или в консоли показателей после тщательной настройки. увеличьте все возможные показатели в вашем сервисе. Имейте в виду, что если вы все настроили правильно, вы должны увидеть JSON метрики в группе журналов для вашей Lambda в консоли Cloudwatch Logs.

  • * Важно: хотя это и не показано в этом примере, очень важно не вызывать MetricsLogger.putDimensions() в вашем методе обработчика, а вместо этого вызывать его в конструкторе ваших лямбда-выражений. Каждый последующий вызов MetricsLogger.putDimensions() будет добавлять новый набор измерений в JSON, который выводится в Cloudwatch, что впоследствии приведет к неверным суммам ваших показателей. Это связано с тем, что значения будут записываться несколько раз, когда один и тот же экземпляр Lambda вызывается несколько раз подряд, пока он еще теплый. Посмотрите, как поле «Размеры» в приведенном ниже JSON имеет два индекса в результате вызова Lambda два раза подряд, когда измерения добавляются в методе обработчика. Если бы он был вызван снова, тогда было бы три индекса, и статистика SUM для метрики была бы втрое больше правильного значения, когда мы перейдем к ее графику.

III. Создание панелей мониторинга показателей в CDK

Одна из самых полезных вещей, которые могут помочь нам как разработчикам в диагностике проблем в наших службах, - это панели инструментов вместе с сигналами тревоги, которые сообщают нам, когда следует иди взгляни на эти дашборды! К счастью, Cloud Development Kit (CDK) позволяет нам легко создавать эти информационные панели и сигналы тревоги при развертывании остальной части нашей инфраструктуры. Все, что требуется, - это знать метрики, которые будут генерироваться нашими функциями (некоторые из которых генерируются по умолчанию), и определить, когда эти метрики должны быть активированы. Возьмем, к примеру, следующий фрагмент кода,

public FunctionDashboard(Construct scope, String id, FunctionDashboardProps props) {
    super(scope, id, DashboardProps.builder()
        .dashboardName(props.dashboardName)
        .build());
        
    Map<String, String> dimensions = /* Your dimensions */
    Metric noSlotsFoundMetric = new Metric(MetricProps.builder()
        .metricName("NoSlotsFound")
        .namespace(EMF_NAMESPACE)
        .dimensionsMap(dimensions)
        .period(Duration.minutes(5))
        .statistic("SUM")
        .label("GetSlots When Farm Has No Slots")
        .build());
        
    GraphWidget noSlotsFoundWidget = new GraphWidget(GraphWidgetProps.builder()
        .height(STANDARD_WIDGET_HEIGHT)
        .width(HALF_DASHBOARD_WIDTH)
        .left(List.of(noSlotsFoundMetric))
        .title(props.getSlotsApiMethodName + "-NoSlotsFound")
        .build());
        
    this.addWidgets(noSlotsFoundWidget)
}

Этот фрагмент кода создает объект Metrics, который используется как своего рода маркер для отслеживания метрик, генерируемых лямбда-функцией. Обратите внимание, что на самом деле он не создает метрики, поскольку они генерируются Lambda. Однако мы передаем эту метрику в объект GraphWidget, который создает график метрики на нашей информационной панели, когда мы вызываем this.addWidgets().

Здесь важно отметить, что есть ряд параметров, которые автоматически добавляются к нашим специальным показателям, когда мы используем формат встроенных показателей. Вы можете добавить эти измерения в свои лямбды, вызвав MetricsLogger.putDimensions(), или вы можете полностью перезаписать их, используя MetricsLogger.setDimensions(). Любая альтернатива работает, просто помните, что вам нужно передать точный набор измерений в объект Metric, чтобы добавить метрику на панель инструментов. Лично я бы рекомендовал переопределить размеры по умолчанию и просто добавить свои собственные, поскольку размеры по умолчанию требуют, чтобы вы отслеживали больше значений в вашем коде, и их обычно довольно легко связать с вашими функциями независимо.

Вы также можете спроектировать макет своей информационной панели, чтобы ее было легче читать с первого взгляда. Например, вы можете сделать график, занимающий всю ширину панели инструментов, или разместить несколько виджетов рядом. Просто имейте в виду, что порядок, в котором вы передаете виджеты в addWidgets(), соответствует порядку, в котором они будут отображаться на вашей панели инструментов. После того, как вы закончите добавлять виджеты на свою панель инструментов, у вас будет что-то вроде того, что показано ниже, где вы можете легко отслеживать, что происходит в вашем сервисе.

IV. Создание сигналов тревоги и уведомлений

После того, как вы настроили свои метрики и информационные панели, вы захотите создать несколько сигналов тревоги для этих показателей. Сигналы тревоги - это удобный инструмент в Cloudwatch, который позволяет быстро увидеть, когда показатель достигает опасного порога. Их также можно использовать в качестве триггеров для отправки уведомлений операционной группе, когда что-то идет не так с сервисом. По сути, они являются важным компонентом, позволяющим вам быстро реагировать на проблемы.

На приведенном выше изображении панели инструментов вы заметите, что на некоторых графиках есть красные линии. Они показывают сигналы тревоги, которые были созданы на основе этих показателей. Настроить эти сигналы так же просто, как создать показатели и графики на панели управления. Все, что нужно сделать, это создать тревогу в вашем CDK и передать метрику, используемую для срабатывания этой тревоги. Затем вам просто нужно указать порог, при котором срабатывает тревога, что влечет за собой установку порогового значения и количества периодов оценки. Порог - это значение метрики, при котором срабатывает тревога, а периоды оценки - это количество раз, когда метрика должна быть выбрана на уровне или выше этого значения, чтобы сработал тревожный сигнал. Вы также можете указать другой оператор сравнения, если вам нужно подавать сигнал тревоги, когда показатель опускается ниже определенного уровня.

Metric errorsMetric = new Metric(MetricProps.builder()
    .metricName("Errors")
    .namespace(LAMBDA_NAMESPACE)
    .dimensionsMap(Map.of("FunctionName", functionName))
    .period(Duration.minutes(5))
    .statistic("SUM")
    .label("Number of Errors")
    .build());
    
Alarm errorsAlarm = new Alarm(this, apiMethodName + "ErrorsAlarm", AlarmProps.builder()
    .alarmName(functionName + "-ErrorsAlarm")
    .metric(errorsMetric)
    .evaluationPeriods(1)
    .threshold(2)
    .build());

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

AlarmWidget errorsWidget = new AlarmWidget(AlarmWidgetProps.builder()
        .height(STANDARD_WIDGET_HEIGHT)
        .width(HALF_DASHBOARD_WIDTH)
        .alarm(errorsAlarm)
        .title(apiMethodName + "-Errors")
        .build());
this.addWidgets(errorsWidget);

Создание уведомлений для ваших будильников

После того, как вы создали все свои будильники и добавили их на свои информационные панели, вам нужно будет настроить уведомления для этих будильников. Никто не хочет постоянно проверять приборную панель весь день, чтобы увидеть, не что-то пошло не так - или, что еще хуже, полностью пропустить катастрофическое событие. Чтобы создать эти уведомления, вы можете настроить темы Simple Notification Service (SNS) и заставить ваши будильники отправлять им сообщения всякий раз, когда они запускаются. Затем вы можете подписаться на электронную почту по этой теме, чтобы каждый раз, когда срабатывает один из ваших будильников, вы сразу же получали уведомление. Опять же, это легко сделать через CDK.

Topic errorAlarmTopic = new Topic(this, "ErrorAlarmTopic", TopicProps.builder()
        .topicName("ErrorAlarmTopic")
        .build());

errorAlarmTopic.addSubscription(new EmailSubscription(props.alertEmail));
errorsAlarm.addAlarmAction(new SnsAction(errorAlarmTopic));

В приведенном выше коде props.alertEmail передается в CDK как переменная контекста. Я порекомендую вам настроить только одну тему для всех ваших будильников. Затем сделайте так, чтобы в каждый из ваших будильников добавлялись действия по тревоге для этой единственной темы. Если вы настроите отдельную тему для каждого из своих будильников, то вы будете завалены электронными письмами с просьбой подписаться на каждую тему индивидуально. Однако вы можете настроить несколько тем, если хотите, чтобы разные сигналы тревоги передавались разным группам в вашей организации.

Дальнейшие примеры

Чтобы увидеть больше примеров настройки мониторинга в AWS, ознакомьтесь с нашей Службой API доставки, размещенной на Github. Он содержит полный пример бессерверного приложения, написанного на Java, и включает код для всех показатели, сигналы тревоги, и панели управления, которые обсуждались в этом сообщении блога.

Https://github.com/aws-samples/i-love-my-local-farmer/tree/main/DeliveryApi