CNCF (Cloud Native Computing Foundation) — некоммерческая организация и крупнейшее объединение людей и компаний, которое задает стандарты облачных технологий для всего IT-рынка. Это фонд, который создает и поддерживает экосистему проектов с открытым исходным кодом, независимых от поставщиков. Цель CNCF — ускорить развитие облачных технологий и сделать их доступными для всех. 

Сегодня большинство важнейших инструментов в облачных технологиях создаются под эгидой CNCF, например: платформа для оркестрации контейнеров Kubernetes, система мониторинга и алертинга Prometheus, система сбора и анализа журналов Fluentd, пакетный менеджер для Kubernetes Helm и другие проекты. Всего у CNCF насчитывается 173 проекта. Над ними работают ведущие мировые эксперты. Также эти эксперты инвестируют в фонд, чтобы он мог нанимать лучших разработчиков. На данный момент у организации более 223 тысяч участников.

Среди многочисленных участников фонда есть команда экспертов по мониторингу и управлению распределенными системами TAG Observability (Technical Advisory Group Observability). Она занимается разработкой стандартов и рекомендаций по использованию методов и инструментов для обеспечения наблюдаемости (observability) в современных облачных приложениях.

Команда TAG Observability состоит из лучших экспертов — представителей различных компаний и организаций, таких как Google, Amazon, Microsoft, Red Hat и других. У этих специалистов большой инженерный опыт в Observability и облаках. Они постоянно следят за рынком и применяют лучшие практики. Также TAG Observability выпускает вспомогательные материалы для конечных пользователей и руководит проектами CNCF, работающих в рамках TAG.

Одним из разработанных командой материалов является программный документ White Paper про наблюдаемость. Это манифест, который рассказывает, как современная компания должна подходить к наблюдаемости в контексте облачной инфраструктуры. Он собрал в себе лучшие практики рынка, которые помогут выстроить и проработать наблюдаемость в компании или проекте.

В августе 2023 года под руководством группы TAG Observability в экосистеме CNCF была выпущена итоговая версия 1.0 документа по наблюдаемости. Ранние редакции документа были неполными, поэтому на них можно было только ориентироваться. Но теперь он полностью решает задачи по наблюдаемости. Мы перевели итоговую версию документа и рекомендуем ознакомиться с ним всем, кто интересуется этой темой.

Основные положения

Уровень сложности систем и данных, которые обрабатываются каждую секунду, растет, поэтому особое значение приобретает наблюдаемость (observability). Она необходима, чтобы лучше понимать состояние рабочих нагрузок. Сейчас инженер должен не только разбираться в инструментах для наблюдения, но и понимать, как контролировать и мониторить приложения. В условиях повышенных ожиданий клиентов и более жестких целей по уровню обслуживания (SLO) инженеры должны находить причины проблем и устранять их быстрее, чем раньше.

Цель документа — помочь разобраться в основах нативной облачной наблюдаемости. Она содержит высокоуровневый обзор различных видов и паттернов наблюдаемости, которые могут понадобиться при работе с рабочими нагрузками в облаке.

Содержание:

Введение

Что такое наблюдаемость

Observability-сигналы

Корреляция сигналов наблюдаемости

Сценарии использования

Существующие пробелы в области наблюдаемости

Полезные ссылки

Контрибьюторы

Внести свой вклад

Введение

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

Системные администраторы, разработчики и операторы программного обеспечения должны знать как о состоянии приложения в production, так и о состоянии базовой инфраструктуры, на которой оно работает. Также у них должна быть возможность наблюдать эти сигналы со стороны без необходимости включать, например, дополнительный инструментарий в исходный код или устанавливать контрольные точки (breakpoints) на работающий в production код.

Приложения должны проектироваться и создаваться так, чтобы включать в себя соответствующие механизмы, которые позволяют наблюдать за ними со стороны, будь то приложение или человек, не имеющий доступа к ЦОДу (центр обработки данных). Приступать к интеграции таких механизмов следует на начальном этапе — во время проектирования. Часто для этого требуется дополнительный код или автоматизация и оснащение инфраструктуры. Это культурные и технологические изменения в проектировании, которые часто выступают препятствиями для компаний. Также сейчас есть большой выбор методов и инструментов для наблюдаемости, чьи подходы отличаются. При этом они позволяют достичь приемлемого уровня наблюдаемости.

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

Целевая аудитория

Этот документ будет интересен и полезен:

  • инженерам по надежности систем (Site Reliability);

  • DevOps-инженерам;

  • системным администраторам;

  • инженерам-программистам;

  • инженерам по инфраструктуре;

  • разработчикам программного обеспечения.

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

Цели

Внедрение облачных вычислений помогло малым и большим технологическим компаниям оптимизировать затраты, разрабатывать более эффективные продукты и масштабировать их, но принесло и ряд проблем. Так как инфраструктура стала удаленной, временной и глобально распределенной, системные администраторы потеряли контроль над ЦОДами. Компании, в которых раньше администраторы и разработчики преследовали конфликтующие цели, вынуждены переходить к новой культуре, в которой они должны работать как единая команда, которая нацелена на создание надежного программного обеспечения. В результате наблюдения за состоянием Cloud Native-систем возник ряд стратегий и инструментов, которые помогают компаниям поддерживать надежность систем в этой новой реальности.

При проектировании и разработке наблюдаемой системы в нее должны быть встроены функции, которые позволяют отправлять или раскрывать телеметрию наблюдателю. В роли наблюдателя обычно выступает набор инструментов, который отвечает за извлечение содержательной информации из собираемых данных. Альтернативой может стать автоинструментарий, например с привлечением среды исполнения Java, pprof или eBPF. Как правило, телеметрия поступает в виде метрик или логов, а также трассировок, структурированных событий, профилей и дампов сбоев. У каждого типа свое предназначение и практики, и их неправильное применение может привести к новым проблемам при работе с программным обеспечением в глобальном масштабе, например к усталости от алертов (alert fatigue) и чрезмерным затратам.

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

Материал не преследует следующие цели

Этот документ не претендует на роль низкоуровневого руководства по установке и настройке конкретных проектов в области наблюдаемости. Он также не предполагает детального погружения в различные стандарты, такие как распространение контекста W3C, формат Prometheus Exposition (OpenMetrics) или протокол OpenTelemetry (OTLP).

Вместо этого предлагается общий обзор и приводятся ссылки на полезные материалы — документацию к проектам.

Что такое наблюдаемость

Наблюдаемость — желательное свойство системы. Кто-то уже вступил на путь наблюдаемости. Другие читают эту работу только потому, что вокруг все говорят о том, что системы должны быть наблюдаемыми. Правда в том, что наблюдаемость стала модным словом. Как и в случае с другими хайповыми понятиями, каждый считает своим долгом «оставить в ней свой след», не всегда разбираясь в сути. Если вы действительно решили, что наблюдаемость — это всерьез и надолго, прежде попробуем прояснить ее базовую суть.

В теории управления наблюдаемость — это мера того, насколько хорошо внешняя информация о системе позволяет судить о ее внутреннем состоянии. Если отложить теорию в сторону, это функция системы, с помощью которой люди и машины могут наблюдать и понимать ее, основывать свои действия на ее состоянии. Определение наблюдаемости выглядит достаточно просто, но при реализации без конкретной цели бывает сложно решить, какой выход (output) должна иметь система. В этом и возникают сложности.

В самом начале легко копировать чужую работу. В интернете можно найти множество примеров: чарты Helm, плейбуки Ansible, модули Terraform. Достаточно запустить один из таких скриптов, и стек наблюдаемости будет готов к работе всего за несколько минут. Это легко, и это работает. Но мы напоминаем, что наблюдаемость — это не банальное использование «красивых и блестящих» инструментов. Нужно понимать, какую информацию выдает система, а для этого необходима конкретная цель. Часто возникает желание собирать все возможные сведения на всякий случай. Но подобный подход приводит к переизбытку ненужных данных.

Наблюдаемость нужна на всех этапах жизненного цикла разработки системы. Ее можно использовать для тестирования новой функции, мониторинга устойчивости production, сбора сведений о том, как клиенты используют продукт, или при принятии основанных на данных (data-driven) решений о дорожной карте продукта. Определившись с одной из этих целей, можно переходить к выходам — сигналам.

Observability-сигналы

Сигналы — это выходные данные, которые производит система. По ним человек или машина может сделать вывод о ее состоянии. Эти сигналы варьируются от системы к системе и зависят от цели, которую необходимо достичь. Например, это может быть некий показатель на определенный момент времени (температура или объем занятой оперативной памяти) или событие, проходящее через множество компонентов распределенной системы, которое требуется отследить. 

Допустим, вы захотите узнать, какая функция вашей системы наиболее интенсивно задействует ресурсы (процессор, память или диск) в некоторый момент времени или что именно происходило в момент «поломки» системы. В то время как некоторые сигналы могут пересекаться, другие специализируются на определенных аспектах системы. Можно использовать сразу несколько сигналов, наблюдая за некоторой функциональностью с разных сторон, или можно начать с одного и постепенно добавлять остальные.

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

Здесь показаны три основных сигнала, которые помогают классифицировать данные, поступающие от рабочих нагрузок. Не все метрики поддаются семантической агрегации, хотя обычно их можно агрегировать более простым способом или представлять группу событий саму по себе. Шкала объема характеризует типичный объем — хотя с помощью метрик тоже можно получить большие объемы, но это все же несколько сложнее, чем с помощью логов и трассировок.
Здесь показаны три основных сигнала, которые помогают классифицировать данные, поступающие от рабочих нагрузок. Не все метрики поддаются семантической агрегации, хотя обычно их можно агрегировать более простым способом или представлять группу событий саму по себе. Шкала объема характеризует типичный объем — хотя с помощью метрик тоже можно получить большие объемы, но это все же несколько сложнее, чем с помощью логов и трассировок.

Существуют различные способы сбора и обработки сигналов. У них разные требования к ресурсам, необходимым для сбора, хранения и анализа, при этом отличаются и способы наблюдения за системой. Выбор конкретного способа или их всех — это всегда поиск оптимального компромисса, как и остальные задачи в проектировании. В следующих разделах мы подробнее остановимся на каждом типе сигналов. Начнем с общеизвестных метрик, логов и трассировок и закончим профилями приложения и дампами сбоев.

Метрики

Метрики — это числовое представление данных. Они делятся на две основные категории: изначально числовые данные и данные, преобразованные (агрегированные) в числа. Примером первой может служить температура, второй — счетчик HTTP-запросов, наблюдаемых на веб-сервере.

Числа — наиболее эффективный способ хранения данных, и все развитые отрасли со временем переходят на метрические показатели. Например, ваши счета за аренду, воду, отопление, охлаждение и электроэнергию — это метрики, как и банковский счет, с которого вы их оплачиваете.

Рассмотрим типичный пример использования метрик — индикатор использования heap-памяти на хосте, например, виртуальной машины. Назовем его heap-memory-bytes. Метрика состоит из имени, набора лейблов, иногда называемых атрибутами или тегами, и числового значения для каждого момента времени, например одно значение в секунду. Экземпляр метрики с определенным именем и лейблами часто называют временным рядом или потоком (stream).

Показатель heap-memory-bytes позволит отслеживать использование heap-памяти на каждом хосте с течением времени. Также можно произвести дополнительное агрегирование, например определить среднее использование heap-памяти для каждого датацентра:

Имя метрики

Ключ лейбла

Значение лейбла

Ключ лейбла

Значение лейбла

Значение в момент времени t0

Значение в момент t1

heap-memory-bytes

host

host123

data-center

c1

11231

11200

heap-memory-bytes

host

host234

data-center

c1

300203

412103

Здесь приведены примеры двух временных рядов для одной метрики. Их имена, лейблы и значения для определенных временных отметок представлены в столбцах.

Переработанные данные теряют часть подробностей. Метрики представляют собой точечные наблюдения за состоянием системы. Это означает, что в примере с heap-memory-bytes ничего нельзя сказать о heap-памяти в промежутках между наблюдаемыми интервалами — между t0 и t1. Также невозможно добиться более высокой гранулярности (подробностей) — все данные приводятся в расчете на хост: нельзя ничего сказать о том, сколько heap-памяти приходится на процесс с определенным ID. Этим они отличаются от логов или трассировок, в которых основное внимание уделяется записям или информации об отдельных событиях с высокой детализацией, например «процесс A занял 20 байт на хосте B».

При использовании по назначению (см. проблему кардинальности) вполне можно пойти на этот компромисс. Так метрики становятся одним из наиболее эффективных сигналов для известных неизвестных:

  • Метрики эффективны с точки зрения предсказуемых затрат на удержание, извлечение, передачу и хранение, так как их объем не увеличивается с ростом трафика. Например, для каждого хоста всегда существует лишь одна метрика heap-memory-bytes независимо от количества занятых ресурсов или запущенных процессов.

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

Отрасль также пришла к выводу, что для разных наблюдений подходят разные типы метрик. Различные модели данных описывают множество разных типов, однако можно выделить три основных, которые поддерживаются повсеместно:

  • Gauge (Индикатор) — метрика, представляющая собой одно числовое значение, которое может произвольно увеличиваться или уменьшаться. Шкалы обычно используются для измерения таких величин, как температура или текущее потребление памяти, а также для показателей, которые могут увеличиваться и уменьшаться, например количество параллельных запросов.

  • Counter (Счетчик) — кумулятивная метрика, представляющая собой один монотонно возрастающий счетчик, значение которого может только увеличиваться или обнуляться при перезапуске. Например, счетчик может предоставлять количество обслуженных запросов, выполненных заданий или ошибок.

  • Histogram (Гистограмма) — производит выборку наблюдений, например длительности запросов или размеров ответов, распределяет по настраиваемым или экспоненциальным интервалам (bucket) и подсчитывает их. Также она позволяет подсчитать сумму всех наблюдаемых значений и провести расширенный анализ распределенных наблюдений, такой как процентили и тепловые карты (heatmap).

Метрики обычно структурированы или полуструктурированы и используются двумя способами:

  • Мониторинг и оповещение в реальном времени. Наиболее распространенный вариант использования метрик — обзор и детализация визуальных дашбордов. Этот способ также используется для инициирования алертов или уведомлений для людей или автоматизированных систем о том, что контролируемая система пересекла некий порог или ведет себя аномально.

  • Тенденции и анализ. Метрики используются для анализа трендов и долгосрочного планирования. Также они позволяют получить информацию о том, как произошел инцидент и как он был устранен. Другая их задача — мониторинг причин с целью предотвратить повторение инцидента.

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

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

В экосистеме CNCF популярны две модели представления данных метрик: Prometheus и OpenTelemetry.

Кардинальность метрик

Важной характеристикой собираемых метрик рабочих нагрузок является кардинальность. Обычно для метрик она означает количество уникальных серий данных, собранных за определенный период. В таблице выше представлена метрика с кардинальностью 2 для периода t0–t1. Но если бы у нас было 100 датацентров с 10 000 хостов в каждом, за тот же период мы бы произвели один миллион метрических рядов (кардинальность = 1 000 000).

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

Любой эффективный бэкенд для хранения метрик или вендор масштабируется с ростом кардинальности метрик — истинные затраты растут с ростом кардинальности. Учитывая, что типичный интервал для метрик варьируется от одной секунды до одной минуты, число выборок может также представлять кардинальность для определенной длительности. Именно поэтому некоторые вендоры и системы взимают плату за число выборок. Многие системы также накладывают ограничения на размер кардинальности за определенное время.

Какой уровень кардинальности оптимален? Универсальной цифры не существует, так как она зависит от ваших потребностей и от того, сколько вы готовы потратить на метрики. Кардинальность может оказаться слишком высокой — придется платить больше или масштабировать хранилище метрик. При этом «дорогие» измерения (с большим количеством уникальных значений) не будут давать достаточной отдачи за свою цену.

Предположим, что мы хотим, чтобы heap-memory-bytes отслеживала потребление памяти для каждого приложения. Первая идея — добавить в метрику лейбл PID (идентификатор процесса).

Имя метрики

Ключ лейбла

Значен-ие лейбла

Ключ лейбла

Значен-ие лейбла

Ключ лейбла

Значен-ие лейбла

Значен-ие в момент времени t0

Значен-ие в момент времени t1

heap-memory-bytes

host

host123

PID

22

data-center

c1

3445

3445

heap-memory-bytes

host

host123

PID

24

data-center

c1

231

190

heap-memory-bytes

host

host123

PID

44

data-center

c1

51331

22340

heap-memory-bytes

host

host234

PID

34

data-center

c1

300203

412103

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

Такая реализация метрики попадает в серую зону, так как ее кардинальность практически не ограничена. Например, в 64-битных системах число возможных PID достигает четырех миллионов, и каждый перезапуск приложения будет давать новый уникальный PID. Предположим, что в течение одного дня в каждом ЦОДе работает по сто приложений с тремя репликами в среднем. В этом случае включение лейбла PID в метрику может привести к тому, что ее кардинальность может достигать миллиардов, а то и сотен миллиардов временных рядов. Худший случай — когда приложения часто перезапускаются.

Так как нас интересует память, используемая определенными репликами приложений, в нашем примере не нужен PID, поскольку можно идентифицировать конкретное приложение. Если бы можно было идентифицировать реплику по некоторому идентификатору, например по имени пода в Kubernetes, и добавить ID реплики вместо лейбла PID, тогда кардинальность сократилась бы максимум до 300 миллионов серий для heap-memory-bytes. Если дополнительно убрать лейбл хоста, кардинальность и стоимость можно уменьшить всего до 30 000, то есть до 300 (число всех реплик) * 100 (количество датацентров)

Добавление лейбла PID может привести к неограниченной кардинальности, но все зависит от характеристик вашей инфраструктуры. Это может быть как осознанный риск, так и случайный взрыв кардинальности метрики — неожиданное число серий, которое приводит к проблемам с масштабируемостью или скачкам затрат.

Кардинальность часто называют ахиллесовой пятой метрик. Это не совсем верно, поскольку каждая единица наблюдаемых данных имеет свою цену. Эффективность метрик обусловлена стабильностью размерностей и их значений во времени.

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

Логи

Логи — это одна или несколько текстовых записей, которые описывают паттерны использования, действия и операции в операционной системе, приложении, сервере или ином устройстве.

Логи можно разделить на следующие категории:

  • Логи приложений. Лог приложения создается, когда в приложении происходит какое-либо событие. Помогает разработчикам понять и оценить поведение приложения в процессе разработки и после релиза.

  • Лог безопасности. Логи безопасности создаются в ответ на события в системе, связанные с безопасностью. Например, это может быть неудачный логин, изменение пароля, неудачный запрос на аутентификацию, доступ к ресурсам, изменение ресурсов (включая файлы, устройства и пользователей) и другие административные изменения. Системные администраторы обычно решают, какие события будут включаться в лог безопасности.

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

  • Лог аудита. Является записью событий и изменений. Обычно в нем фиксируются события: кто выполнил некоторое действие, какое именно действие было выполнено и как отреагировала система. Системный администратор определяет, какая именно информация будет попадать в лог аудита, исходя из бизнес-требований.

  • Лог инфраструктуры. Жизненно важная часть процесса управления инфраструктурой, которая включает в себя управление физическим и логическим оборудованием, составляющим ИТ-основу организации. Это может быть оборудование как категории on-premises, так и облачное. А информация может собираться через API, Syslog или с помощью агентов на хостах.

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

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

Система уровней для логов позволяет присвоить каждой записи определенную важность. Например, уровни могут быть следующими: ERROR, WARNING, INFO и DEBUG. При этом уровень ERROR является наименее подробным, а DEBUG — наиболее подробным.

  1. ERROR сообщает о факте сбоя и содержит подробности о том, почему тот произошел.

  2. WARNING — высокоуровневое сообщение, требующее внимания. Но это не сбой.

  3. INFO — эти сообщения помогают понять, как работает система.

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

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

Форвардинг логов можно осуществлять несколькими способами. Прежде всего рекомендуется настроить стандартные потоки для отправки логов в некое центральное место. Далее можно сохранять логи в очередь сообщений для фильтрации и дополнения перед перемещением в конечный пункт. Наконец, можно воспользоваться Open Source-сборщиком данных для отправки логов в центральное хранилище. Комбинируйте логи с другими observability-сигналами, чтобы получить полное представление о системе.

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

Трассировки

Распределенная трассировка помогает понять, что произошло во время распределенной транзакции, например запроса, инициированного пользователем, и оценить его влияние на все затронутые downstream-микросервисы и хранилища данных.

Трассировки обычно представляют собой последовательности «точек данных», или спанов (span), и визуализируются с помощью диаграммы Ганта, как на примере ниже:

Интерфейс проекта Jaeger, который визуализирует спаны для заданной трассировки
Интерфейс проекта Jaeger, который визуализирует спаны для заданной трассировки

Трассировки обычно относятся к конкретной транзакции — пути, по которому «шел» запрос в конкретной программе, что делает их observability-сигналами высокого разрешения. Спаны сильно привязаны к контексту. Кроме того, спаны записывают информацию о родительском спане, который их инициировал. Это позволяет проследить причинно-следственные связи между различными элементами распределенной системы, такими как сервисы, очереди, базы данных и т. п.

Ключевым механизмом сохранения отношений между различными участниками является перенос контекста. Многие мониторинговые системы предлагают собственные способы распространения контекста трассировки, при этом в целом представители отрасли убеждены, что распространение trace-контекста должно осуществляться стандартизированным способом. Именно для этого была создана рабочая группа W3C Distributed Tracing Working Group, которая разработала спецификацию W3C Trace Context Specification. W3C Trace Context определяет стандартные HTTP-заголовки и формат значений для распространения контекстной информации. Это позволяет реализовать сценарии распределенной трассировки. Спецификация стандартизирует способ передачи и изменения контекстной информации между сервисами. Контекст однозначно идентифицирует отдельные запросы в распределенной системе и определяет способы добавления и передачи контекстной информации, специфичной для провайдера.

Сегодня W3C Trace Context стандартно используется в OpenTelemetry или платформе .NET. Следует ожидать, что поставщики облачной инфраструктуры также начнут поддерживать данный формат, чтобы сохранить контекст при прохождении через managed-сервисы вроде сервисных шлюзов.

Инструментарий важен для всех сигналов наблюдаемости, но в распределенной трассировке он играет первостепенную роль, учитывая ее сложность. Инструментарий создает опорные точки данных и продвигает контекст от сервиса к сервису. Без передачи контекста невозможно связать входящий HTTP-запрос с последующими исходящими downstream-HTTP-запросами, равно как и производителя сообщения с его потребителями.

У инструментария две основные цели в распределенной трассировке: передача контекста и картирование спанов. В большинстве случаев распространение контекста осуществляется прозрачно с помощью библиотек, которые могут быть интегрированы в HTTP-клиенты и серверы. В этой части могут пригодиться такие проекты и технологии, как OpenTelemetry API/SDK.

Связь спанов при сетевых вызовах
Связь спанов при сетевых вызовах

Профили

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

Существуют профайлеры под разные варианты использования и ресурсы:

  • профайлеры CPU;

  • heap-профайлеры;

  • профайлеры GPU;

  • мьютекс-профайлеры;

  • профайлеры IO;

  • профайлеры для конкретного языка, например JVM-профайлер.

Каждая из этих категорий делится на множество подтипов, но все они преследуют одну цель — проанализировать, как некий ресурс используется в системе.

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

Добавление оси «времени» к результатам профилирования повышает детализацию и полезность статических профилей и позволяет анализировать данные во всех подробностях, формируя целостную картину. Комплексное понимание ресурсов становится все более важным при оптимизации/отладке Cloud Native-приложений и планировании распределения ресурсов.

Подобно тому, как трассировка помогает понять, какая часть приложения ответственна за задержку, профилирование позволяет углубиться и выяснить, откуда берутся проблемы с задержкой. Более того, оно помогает понять, какие части кода самые «голодные» в плане серверных ресурсов.

Профайлы, генерируемые средами исполнения (runtime), обычно включают в себя подробную статистику вплоть до номера строки, поэтому они прекрасно подходят для перехода от «что?» к «почему?» с точки зрения кода.

Пример иерархического графика (icicle graph) для CPU-профиля приложения, написанного на языке Go
Пример иерархического графика (icicle graph) для CPU-профиля приложения, написанного на языке Go

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

Дампы

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

Например, приложения, которые работают с большими объемами данных, могут генерировать дамп-файлы размером в десятки гигабайт. В системах на базе Linux файлы дампа могут сохраняться в любое место (его можно задать с помощью глобального параметра /proc/sys/kernel/core_pattern). Начиная с ядра 2.6, появился новый метод работы с дампами памяти — так называемые обработчики дампов. Теперь за создание файла дампа отвечает не операционная система: вместо этого вывод «упавшего» процесса передается на стандартный вход приложения, которое и отвечает за запись файла. 

Например, в дистрибутивах на базе Ubuntu это можно сделать с поддержкой как systemd, так и abort. Дистрибутивы на основе RedHat используют так называемый ABRT. 

На сегодняшний день сообществу Cloud Native все еще необходима помощь со сбором дампов памяти. На то существуют как минимум две основные причины:

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

  • Сохранение данных является неотъемлемой частью нативных облачных окружений: сбойное приложение (под) нуждается в посторонней помощи для записи файла дампа на постоянный том. 

Более шести лет назад в сообщество разработчиков ядра Linux был внесен RFC (https://lore.kernel.org/patchwork/patch/643798/) об индивидуальном для каждого пространства имен параметре core_pattern вместо глобального параметра. Кроме того, в сообществе Docker имеется Issue примерно того же возраста (moby/moby#19289) о поддержке core_pattern в Docker.

Корреляция сигналов наблюдаемости

Наблюдаемость — комплексная тема. Чтобы больше знать о состоянии и поведении программного обеспечения, собираются различные типы данных под разными ракурсами, с разными интервалами и пайплайнами: метрики, логи, трейсы, профили и core-дампы.

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

  • Метрики заточены под надежный и дешевый мониторинг и аналитику в реальном времени — основа надежной системы. 

  • Логи обеспечивают нам более глубокое понимание мелких деталей работающей системы, давая контекст. 

  • В какой-то момент детали образуют дерево запросов, и в дело вступает распределенная трассировка с ее спанами и передачей контекста между процессами. 

  • Иногда требуется погрузиться еще глубже — профили приложений помогают обнаружить неэффективные кусочки кода с завышенным ресурсным аппетитом. 

  • Захват дампов позволяет получить ценные сведения о сбоях в работе приложений.

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

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

Если учитывать, что сигналов наблюдаемости может быть до четырех и более, пользователям observability-системы придется потратить немало времени на изучение различных пользовательских интерфейсов и API для каждого сигнала. Нередко пользователи пытаются идти коротким путем и, например, не используют трассировку или профилирование, если знакомы только с метриками и логированием.

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

Корреляция сигналов

Существуют два основных подхода к соотнесению данных:

  • В одном вы изначально выстраиваете связи самостоятельно.

  • В другом вы вынуждены использовать уже имеющиеся данные.

При любой возможности следует использовать одну и ту же структуру метаданных для всех сигналов наблюдаемости. Например, если вы работаете с Kubernetes или Prometheus, вы уже наверняка используете лейблы для своих метрик. По возможности используйте те же самые лейблы и для логов.

Если же выстраивать связи приходится самостоятельно, рассмотрим общие данные, которые прикрепляются ко всем сигналам:

Взаимосвязь четырех сигналов наблюдаемости
Взаимосвязь четырех сигналов наблюдаемости

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

Переход от одного сигнала наблюдаемости к другому с помощью единых метаданных цели
Переход от одного сигнала наблюдаемости к другому с помощью единых метаданных цели

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

Еще иногда к трассировке и логам привязаны дополнительные подробности. Распределенная трассировка так мощна благодаря тому, что все спаны привязаны к одному trace ID. Эта информация аккуратно передается от функции к функции, от процесса к процессу и связывает операции для определенного пользовательского запроса. Нередко эта же информация (идентификатор запроса/операции — Request ID или Operation ID) записывается в элемент лога, который связан с запросом. Если убедиться, что эти идентификаторы одинаковы в логах и трассировках, можно прочно связать обе категории сигналов на самом низком уровне. В результате можно легко перемещаться между строками лога и отслеживать спаны и теги, которые привязаны к отдельному запросу.

Переход между логами и трассировками по идентификатору запроса или операции
Переход между логами и трассировками по идентификатору запроса или операции

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

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

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

Схема выше показывает возможные связи с использованием целевых метаданных, идентификатора запроса или операции, а также exemplar'ов
Схема выше показывает возможные связи с использованием целевых метаданных, идентификатора запроса или операции, а также exemplar'ов

В идеальной observability-системе можно использовать все звенья цепочки, что обеспечивает гибкость в том, как ведется наблюдение за ней с разных точек зрения/сигналов.

Теоретически exemplar'ы можно прикреплять и к профилям. Но, если учитывать их специфику и варианты использования (отладка производительности в процессе работы), необходимость связать профиль с запросом или операцией возникает нечасто. Это поможет нам отслеживать записи в логе.

Практическое применение

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

Пример диагностики, которая начинается с алерта и использует плавные корреляции наблюдаемости
Пример диагностики, которая начинается с алерта и использует плавные корреляции наблюдаемости

Допустим, поступил алерт о неожиданно высокой частоте ошибок, которая превышает SLO. Алерт основан на счетчике ошибок: заметен всплеск запросов, которые завершаются HTTP code 501. С помощью exemplar'а можно перейти к записи в логе, которая содержит понятное и конкретное сообщение об ошибке. Оказывается, источником ошибки является внутренний микросервис. ID запроса, который совпадает с ID трассировки, позволяет перейти к последней и установить, какой сервис/процесс является источником проблемы.

Другой пример диагностики, которая начинается с трассировки и использует корреляцию метаданных цели
Другой пример диагностики, которая начинается с трассировки и использует корреляцию метаданных цели

Допустим, идет работа над устранением медленных запросов. Для этого вручную инициируются запросы с выборкой трассировки, соответственно, доступен ID трассировки. Трассировка показывает, что запрос ABC-1 отработал слишком медленно для базовых операций. Ориентируясь на метаданные цели и момент времени, мы выбираем соответствующие показатели использования CPU. Близкое к предельному использование CPU указывает на насыщение процессора. Чтобы узнать причину, учитывая, что это единственный процесс в контейнере, можно перейти к профилю CPU с помощью метаданных цели и момента времени.

Практические реализации

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

1. Единые метаданные цели прикрепляются ко всем сигналам.

Согласованные метаданные необходимы для переключения между observability-сигналами от одной цели, например от приложения. В этом случае можно применять такие pull-системы, как Prometheus или OpenTelemetry Prometheus receiver (метрики), сборщиков логов (OpenTelemetry, Fluentd, Fluent Bit), при этом сохранять единообразие целевых лейблов или атрибутов, например cluster, environment, pod и container_name, которые навешиваются сборщиком или агентом. При работе с push-системами вроде OTLP (метрики, логи и трассировка) инструментируемое приложение обычно присоединяет информацию о цели, при этом обеспечивает согласованность и единообразие.

2. Рассмотрите возможность сделать идентификатор операции (Operation ID), идентификатор запроса (Request ID) или идентификатор трассировки (Trace ID) одним уникальным идентификатором и привязать его к системе логирования (не только трассировки).

Попробуйте объединить клиенты для трассировки и логирования так, чтобы библиотека трассировки генерировала Trace ID, который представляет собой уникальный запрос, проходящий через разные микросервисы. Этот же Trace ID можно прикреплять к записи в логе при регистрации события, которое связано с запросом.

3. Реализуйте поддержку exemplar'ов.

Для этого обычно приходится менять клиентский инструментарий. Это связано с тем, что идентификатор Trace ID, если он валиден, необходимо внедрить в соответствующие метрики, например в гистограмму задержек запросов. Многие клиенты Prometheus, например Go, и SDK OpenTelemetry поддерживают exemplar'ы, поэтому остается только изменить соответствующий инструментирующий код. В будущем могут появиться библиотеки и автоинструментальные решения, которые будут инъектировать exemplar'ы автоматически.

Сценарии использования

Рассмотрим более продвинутое использование и категоризацию наблюдаемости и ее сигналов.

Категории box-based-мониторинга

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

Мониторинг традиционно относился к компетенции системного администратора или оператора (operator, ops). Программное обеспечение не разрабатывалось с расчетом на мониторинг, и операторам приходилось судить о состоянии системы по внешним сигналам, иногда «провоцируя» их — например, проводя зондирование с помощью blackbox-экспортера. Этот подход известен как close-box-мониторинг.

Современный путь — переложить заботу о мониторинге на плечи разработчика, то есть инструментирование кода становится частью процесса разработки. Также теперь мониторинг приносит пользу и самим разработчикам (отладка, оптимизация). Другими словами, необходимо «открыть» эту программную коробку (open-box), так как инструментарий — это ключевой шаг для повышения качества наблюдаемости.

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

Внедрение SLI, SLO и SLA

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

Прежде чем погрузиться в детали реализации, объясним определения, так как они бывают запутанными и иногда используются как взаимозаменяемые:

  • Показатель уровня обслуживания (Service Level Indicator, SLI) — тщательно определенная количественная мера (обычно метрика) некоторого аспекта уровня предоставляемого сервиса, например задержки или частоты ошибок в данный момент.

  • Цель по уровню обслуживания (Service Level Objective, SLO) — цель, которая определяет, как часто допустимы перебои в работе. Целевое значение или диапазон значений для уровня обслуживания, который измеряется SLI. Обычно на начальном этапе ставят достаточно жесткую SLO. В дальнейшем ее корректируют. Это полезно не только для последующей доработки SLA, но и для постановки целей в области разработки.

  • Соглашение об уровне обслуживания (Service Level Agreement, SLA) — деловой контракт, который включает в себя последствия нарушения SLO, или его несколько смягченная версия.

  • Бюджет ошибок (Error budget) — допустимые сбои за период, определяемый SLO. Вычисляется как 100% минус SLO за определенный промежуток времени, например за месяц.

Подробнее читайте в книге Google SRE.

Чтобы предлагаемый SLO был полезным и эффективным, все заинтересованные стороны должны с ним согласиться:

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

  • Разработчики продукта должны взять на себя обязательства по повышению уровня сервиса и снижению риска для пользователей в случае исчерпания бюджета ошибок. 

  • Команда, которая отвечает за production-окружение и соблюдение SLO, должна дать свою оценку: возможно ли реализовать поставленную цель без чрезмерных усилий и риска выгорания, так как эти эффекты вредят долгосрочному здоровью команды и ее работе.

Шаги для определения SLI, SLO и SLA
Шаги для определения SLI, SLO и SLA

Алерты на основе observability-данных

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

Во временных рядах метрик есть много сигналов, на основе которых можно генерировать алерты, и многие из них, скорее всего, будут связаны с конкретным приложением. Рекомендуемая практика — использование SLO-команды в качестве основы для алертов. Как упоминалось выше, SLO — это целевое значение или диапазон значений для уровня обслуживания, который измеряется показателем уровня обслуживания (SLI). Например, SLO для REST API может быть таким: 95% запросов должны обслуживаться менее чем за 500 миллисекунд. Необходимо также определить бюджеты ошибок, чтобы алерты для команды были эффективными. Мы рассмотрим способы объединения SLO и бюджетов ошибок для создания действительно полезных алертов.

Алерты на практике

Построение алертов — сложный процесс. Он подвергается риску большого числа ложных срабатываний и развитию «усталости от алертов». Алерты должны быть действенными и указывать на проблему, которая требует решения.

Еще алерты бывают разной степени критичности — не все они одинаково важны. Например, есть разница между «пейджинговыми» (Прим. пер.: от «пейджер» — ранее это устройство использовали для срочного вызова, например, медицинских специалистов) и «тикетными» алертами. Терминология здесь сильно разнится. Некоторые говорят «алерт», подразумевая именно «пейдж» — вмешательство настолько необходимо, что человека следует разбудить.

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

Ниже мы рассмотрим три подхода, которые можно реализовать: простой, на основе скорости исчерпания и на основе ML-моделей.

Целевая частота ошибок

Распространенный подход — оповещение по целевому уровню ошибок. Для его реализации следует выбрать небольшое временное окно, например десять минут. Алерт генерируется, если частота ошибок в этом окне превышает SLO.

Например, при SLO 99,9% алерт будет генерироваться в том случае, если частота ошибок за последние десять минут превышает 0,1%. В Prometheus это может выглядеть примерно так (общее количество ошибок HTTP-запросов, деленное на сумму всех запросов за последние 10 минут):

(sum(rate(http_requests_total{code=~"5.*"}[10m])) / sum(rate(http_requests_total[10m]))) > 0.001

Преимущество данного подхода в его скорости и простоте. Также логика алерта достаточно очевидна и прозрачна. Но есть риск генерации слишком большого числа подобных алертов, которые не нарушают условия SLO.

Скорость исчерпания

Алерты на основе скорости исчерпания (burn rate) — улучшенный метод, способный генерировать более толковые оповещения. Сначала определим, что такое скорость исчерпания (burn rate) и бюджет ошибок (error budget).

Концепция бюджета ошибок присутствует во всех определениях SLO. В 99,9% SLO неявно указывает на то, что сбои могут занимать 0,1% от заранее определенного периода времени («окно» SLO). «Скорость исчерпания — это то, насколько быстро по отношению к SLO сервис расходует бюджет на ошибки» [8]. Например, «скорость исчерпания, равная 1, означает, что бюджет будет полностью исчерпан в момент окончания окна SLO. Так, если SLO равен 99,9%, а период времени составляет 30 дней, то при скорости исчерпания, равной 1, бюджет на ошибки иссякнет через 30 дней». [8]

Показано, как быстро иссякнет бюджет ошибок в зависимости от скорости исчерпания
Показано, как быстро иссякнет бюджет ошибок в зависимости от скорости исчерпания

Скорость исчерпания

Частота ошибок при SLO 99,9%

Время до исчерпания

1

0,1%

30 дней

2

0,2%

15 дней

10

1%

3 дней

1000

100%

43 минуты

В этой таблице приведены нормы исчерпания и время до полного исчерпания бюджета.

Скорость исчерпания позволяет уменьшить размер окна и создать алерт заранее и с высокой точностью. В случае нашего примера предположим, что окно составляет один час, а расходование 5% бюджета — достаточно важное событие, чтобы оповестить о нем оператора. На основании этих данных можно определить целевую скорость исчерпания, при достижении которой будет сгенерирован алерт.

Для алертов на основе скорости исчерпания время срабатывания алерта составит:

(1 – SLO / процент ошибок) * размер окна * скорость исчерпания

А доля использованного бюджета ошибок к моменту срабатывания алерта составит:

(скорость исчерпания * размер окна) / период времени

Так, если 5% бюджета ошибок на 30 дней будут потрачены в течение 1 часа, скорость исчерпания составит 36. Теперь можно задать правило для срабатывания алерта:

(sum(rate(http_requests_total{code=~"5.*"}[1h])) / sum(rate(http_requests_total[1h]))) > 36 * .001

Обнаружение аномалий

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

Хотя механизм оповещений на базе пороговых значений позволяет настраивать алерты на основе известных значений, они могут быть негибкими и неадаптируемыми к изменениям в данных, вызванным сезонностью, текущими развертываниями и другими сценариями.

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

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

Анализ первопричин

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

Существующие пробелы в области наблюдаемости

В этом разделе мы рассматриваем области экосистемы CNCF, связанные с наблюдаемостью, которые требуют дополнительной проработки. Относитесь к этому разделу как к списку готовых идей для перспективного проекта, нового стандарта, статьи в блоге или даже бизнеса.

Возможно, у кого-то есть ответы на некоторые из затронутых вопросов, и он может внести свой вклад в подготовку данного технического документа. Это приветствуется (подробнее об этом в разделе «Внести свой вклад»).

Со временем мы устраним эти пробелы в Open Source-пространстве CNCF. Далее указаны некоторые из них.

Автоматический и non-intrusive-инструментарий в OSS

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

Стандартизированный уровень запросов

Для observability-систем существуют различные языки, которые предназначены для конкретной области — domain-specific languages (DSL). Причем они плохо согласованы и мало совместимы. Наблюдаемость является одним из основополагающих аспектов разработки, и в настоящее время существует множество систем сбора, хранения и обработки телеметрии. Переход к другому вендору или инструменту остается сложной задачей. Для переноса данных и запросов часто приходится писать специализированные инструменты. Для этого операторам приходится тратить время на изучение тонкостей новой системы наблюдаемости, у которой есть неочевидные отличия от старой. 

Инициатива OpenTelemetry (OTel) обеспечивает взаимодействие между Open Source-проектами/вендорами с точки зрения совместимости клиентов и сбора данных. На примере OTel можно сказать, что еще предстоит работа по стандартизации способов запроса данных и стандартизации схемы/терминологии, которая используется для представления данных.

Больше баз данных наблюдаемости в OSS

Мы признаем, что не все сигналы наблюдаемости легко реализовать, используя только OSS, а также не-AGPL-программы, особенно среди проектов фонда CNCF. Хотя существуют зрелые базы данных для метрик, например Prometheus, Thanos и Cortex, отсутствуют их аналоги «под зонтиком» CNCF для логов, трассировок и профилей. В то же время есть множество хороших решений за пределами CNCF, причем у некоторых из них достаточно мягкие лицензии.

Мониторинг для потоковых API

На сегодняшний день существует несколько хорошо известных методик мониторинга. Например, метод USE, описанный Бренданом Греггом, для мониторинга вычислительных ресурсов. И метод RED, придуманный Томом Уилки, для мониторинга сервисов на основе запросов.

К сожалению, обе методологии трудно реализовать для потоковых API. С ростом популярности потоковых вызовов удаленных процедур, например gRPC, необходимо разработать новую или обновленную методологию и инструментарий для их мониторинга.

Полезные ссылки

  1. HARTMANN, Richard. Talk given at Fosdem (Brussels), Feb 2019. Доступно по адресу: https://archive.fosdem.org/2019/schedule/event/on_observability_2019/. Проверено: June 24, 2021.

  2. SRIDHARAN, Cindy. Distributed Systems Observability. Chapter 04, The Three Pillars of Observability. 2018. Доступно по адресу: https://www.oreilly.com/library/view/distributed-systems-observability/9781492033431/ch04.html. Проверено: June 24, 2021.

  3. BEYER, Betsy; JONES, Chris; MURPHY, Niall; PETOFF, Jennifer. Site Reliability Engineering. O'Reilly Media, 2016. Доступно по адресу: https://sre.google/sre-book/table-of-contents/. Проверено: June 24, 2021.

  4. BEYER, Betsy; MURPHY, Niall; RENSIN, David; KAWAHARA, Kent; THORNE, Stephen. The Site Reliability Workbook. O'Reilly Media, 2018. Доступно по адресу: https://sre.google/workbook/table-of-contents/. Проверено: June 24, 2021.

  5. SRIDHARAN, Cindy. Monitoring and Observability. Sep 5, 2017. Доступно по адресу: https://copyconstruct.medium.com/monitoring-and-observability-8417d1952e1c. Проверено: June 24, 2011.

  6. MCCARTHY, Kate; FONG-JONES, Liz; FISHER, Danyel; MAHON, Deirdre; PERKINS, Rachel. Observability Maturity: Community Research Findings Q1, 2020. April, 2020. Доступно по адресу: https://www.honeycomb.io/wp-content/uploads/2020/04/observability-maturity-report-4-3-2020-1-1.pdf. Проверено: June 24, 2021.

  7. Kalman R. E. On the General Theory of Control Systems, Proc. 1st Int. Cong. of IFAC, Moscow 1960 1481, Butterworth, London 1961. Доступно по адресу: https://www.sciencedirect.com/science/article/pii/S1474667017700948?via%3Dihub. Проверено: June 24, 2021.

  8. Li et al. «Situation-Aware Multivariate Time Series Anomaly Detection Through Active Learning and Contrast VAE-Based Models in Large Distributed Systems», in IEEE Journal on Selected Areas in Communications, vol. 40, no. 9, pp. 2746-2765, Sept. 2022, doi: 10.1109/JSAC.2022.3191341.

  9. H. Wang et al. «Groot: An Event-graph-based Approach for Root Cause Analysis in Industrial Settings», 2021 36th IEEE/ACM International Conference on Automated Software Engineering (ASE), Melbourne, Australia, 2021, pp. 419-429, doi: 10.1109/ASE51524.2021.9678708.

Контрибьюторы

Содержание данной White Paper — результат усилий сообщества. Благодаря плановым обсуждениям на встречах раз в две недели, спонтанным дискуссиям в Slack-канале #tag-observability, а также комментариям и предложениям в черновике документа число контрибьюторов в этом проекте оказалось гораздо выше, чем ожидалось. Вот алфавитный список участников, которые помогали нам все это время:

Спасибо всем вам!

Внести свой вклад

Нашли в документе опечатку или недостоверную информацию? Хотите получить дополнительную информацию? Помогите нам развивать и поддерживать этот документ! Вот как это можно сделать:

  • Посмотрите открытые Issues на GitHub, помеченные как актуальные для версии v1.1.

  • Если у вас есть идеи, исправления или предложения, создайте PR или добавьте Issue на GitHub. Убедитесь, что соблюдаются правила американского английского языка. В идеале прогоните свою работу через Grammarly или аналогичные инструменты. Убедитесь, что у сообщения четкие цели, определите, чем именно вы хотите поделиться, фокусируйтесь на полноценных OSS-инструментах и избегайте коротких разделов. По возможности старайтесь интегрировать их в существующие.

  • Присоединяйтесь к нашим встречам TAG Observability Meetings или каналу в Slack и делитесь отзывами и вопросами.

P. S.

Читайте также в нашем блоге:

Комментарии (3)


  1. Sirion
    11.01.2024 10:11
    +4

    А в какое агрегатное состояние агрегированы Петрики?


    1. TimurTukaev
      11.01.2024 10:11
      +1

      В чашку Петри)


  1. alxal
    11.01.2024 10:11
    +1

    Немного не понял про exemplar.
    Как его использовать?
    Кто нибудь разобрался? Можете пример привести. Я раза три прочитал и не понял.