1. Архитектура логирования: переход от метрик к событиям и структура ELK
Архитектура логирования: переход от метрик к событиям и структура ELK
Система мониторинга генерирует критический алерт: метрика http_requests_total с лейблом code="500" показывает скачок до 400 ошибок в секунду. На дашборде Grafana отрисовывается резкий пик, сигнализирующий о деградации сервиса. Prometheus отлично справился со своей задачей — он зафиксировал факт сбоя, масштаб проблемы и время её начала. Но при попытке выяснить причину администратор сталкивается с фундаментальным ограничением Time Series баз данных: Prometheus не знает, почему произошла ошибка. У него нет ни stack trace приложения, ни ID пользователя, вызвавшего сбой, ни тела SQL-запроса, который привел к таймауту. Для ответа на вопрос «почему?» требуется совершенно иной класс данных — события.
Границы применимости: Метрики против Событий
В предыдущем курсе была подробно разобрана архитектура Prometheus и концепция временных рядов (Time Series). Метрика — это агрегированное числовое значение, описывающее состояние системы в конкретный момент времени. Лог-событие (log event) — это дискретная, детализированная запись об одной конкретной транзакции или действии.
Если метрика — это пульс пациента (90 ударов в минуту), то лог — это подробная медицинская карта с описанием каждой биохимической реакции.
Главная проблема, разделяющая эти два мира — кардинальность (cardinality). В Prometheus добавление уникального лейбла (например, user_id или request_id) к метрике создает новый временной ряд. Если сервис обрабатывает миллион уникальных пользователей, TSDB попытается создать миллион временных рядов, что приведет к исчерпанию оперативной памяти (OOM) и падению сервера мониторинга. Метрики обязаны иметь низкую кардинальность.
Логи, напротив, предназначены для хранения данных с бесконечной кардинальностью. Лог-событие может содержать уникальный хэш транзакции, полный текст ошибки на 50 строк и JSON-объект с параметрами запроса.
| Характеристика | Метрики (Prometheus) | Логи (ELK Stack) | | :--- | :--- | :--- | | Структура данных | Число (Float64) + набор строковых лейблов | Текст или вложенный JSON-документ | | Объем на единицу | 1-2 байта на сэмпл | От 100 байт до десятков килобайт на событие | | Кардинальность | Низкая (сотни/тысячи уникальных комбинаций) | Неограниченная (миллионы уникальных ID) | | Основная задача | Алертинг, оценка трендов, Capacity Planning | Дебаггинг, аудит безопасности, форензика | | Поведение при пиках | Нагрузка на сеть стабильна (Pull-модель) | Нагрузка на сеть растет пропорционально трафику |
Математически метрика часто является производной от логов. Значение счетчика ошибок за минуту — это сумма всех индивидуальных лог-событий с уровнем ERROR за этот период:
где — количество сгенерированных событий. Централизованное логирование позволяет провалиться от агрегированного значения к конкретному .
Эволюция боли: от локальных файлов к структурированным данным
Исторически системное администрирование опиралось на локальные текстовые файлы. Поиск проблемы сводился к подключению по SSH и выполнению цепочки команд: tail -f /var/log/syslog | grep -i "oom-killer".
Этот подход ломается при масштабировании инфраструктуры по трем причинам:
trace_id. Сделать это через SSH невозможно.Решением стал переход к структурированному логированию (Structured Logging). Вместо записи текста приложение формирует JSON-объект.
Сравнение плоского лога:
2023-10-25 14:32:01 [ERROR] User 4815 failed to login from 192.168.1.50: Invalid password
И структурированного:
Структурированный формат позволяет базе данных индексировать каждое поле отдельно. Запрос «найти все неудачные логины с IP 192.168.1.50» выполняется за миллисекунды, так как СУБД обращается к конкретному индексу поля source.ip, а не сканирует весь текст.
Анатомия Elastic Stack
Для сбора, преобразования и хранения миллионов структурированных JSON-документов в секунду была создана экосистема ELK, которая позже трансформировалась в Elastic Stack. Аббревиатура ELK описывает три фундаментальных компонента, к которым со временем добавился четвертый.
Elasticsearch: Поисковое ядро
Elasticsearch (ES) — это распределенная NoSQL база данных, построенная поверх библиотеки Apache Lucene. В отличие от реляционных баз (PostgreSQL, MySQL), ES не использует таблицы. Данные хранятся в виде JSON-документов, объединенных в индексы.Главная архитектурная особенность Elasticsearch — использование инвертированного индекса (Inverted Index). При записи документа ES разбивает текстовые поля на отдельные слова (токены) и создает словарь, где каждому слову соответствует список ID документов, в которых оно встречается. Это похоже на предметный указатель в конце книги. Благодаря этому поиск слова "timeout" среди миллиарда логов происходит практически мгновенно — ES не читает документы, он сразу смотрит в словарь и получает список нужных ID.
Logstash: Конвейер обработки (ETL)
Logstash выполняет роль классического ETL-инструмента (Extract, Transform, Load). Это тяжеловесное Java-приложение, которое принимает сырые данные из множества источников, нормализует их и отправляет в Elasticsearch.Задачи Logstash в архитектуре:
Kibana: Визуализация и интерфейс анализа
Kibana — это веб-интерфейс для работы с Elasticsearch. В отличие от Grafana, которая исторически фокусировалась на отрисовке графиков по временным рядам, сильная сторона Kibana — инструмент Discover. Он позволяет интерактивно фильтровать сырые JSON-документы, разворачивать их структуру, искать аномалии в текстах ошибок и переходить от высокоуровневых дашбордов к конкретной строке кода, вызвавшей сбой.Beats: Легковесные агенты доставки
Исторически администраторы устанавливали Logstash прямо на конечные серверы для чтения файлов. Из-за того, что Logstash работает на JVM, он потреблял сотни мегабайт оперативной памяти, что было неприемлемо для серверов приложений.Для решения этой проблемы компания Elastic разработала семейство Beats — агенты, написанные на языке Go (что обеспечивает минимальное потребление CPU и RAM, порядка 15-20 МБ). Самый популярный из них — Filebeat. Его единственная задача — эффективно читать лог-файлы на сервере и отправлять их по сети в Logstash или напрямую в Elasticsearch.
Жизненный цикл лог-события: от диска до дашборда
Чтобы понять, как компоненты взаимодействуют на практике, проследим путь одной строки лога от момента возникновения ошибки до глаз администратора.
502 Bad Gateway в файл /var/log/nginx/error.log.inotify (в Linux), моментально узнает об изменении файла. Он считывает новую строку, запоминает смещение (offset) в файле, чтобы не прочитать её дважды при перезапуске, и упаковывает строку в сетевой пакет для отправки.Архитектурные компромиссы и цена логов
Переход от метрик к централизованному логированию требует значительных инфраструктурных ресурсов. Если Prometheus может мониторить кластер из 100 серверов, потребляя 4 ГБ оперативной памяти и 50 ГБ диска, то ELK Stack для той же инфраструктуры может потребовать кластер из нескольких серверов с десятками гигабайт RAM и терабайтами быстрого хранилища.
Объем генерируемых логов вычисляется по формуле:
где — среднее количество событий в секунду (Rate), — средний размер одного структурированного события в байтах (Size), а — время хранения в секундах (Time).
Если микросервис генерирует 5000 событий в секунду, а один обогащенный JSON-документ весит 1 КБ, то один такой сервис генерирует около 5 МБ логов в секунду, или ~430 ГБ в сутки. В кластере из 20 микросервисов это почти 9 ТБ данных ежедневно.
Это порождает три архитектурных вызова:
Внедрение ELK Stack — это переход от вопроса «что сломалось?» к ответу «почему сломалось и кто виноват?». Однако этот инструмент требует точной настройки конвейера обработки. Сырые неструктурированные данные, сброшенные в Elasticsearch, быстро превратят кластер в медленную и дорогую свалку текста. Чтобы этого избежать, данные необходимо фильтровать и структурировать «на лету», до того как они осядут на дисках СУБД.