Pull to refresh
m2_tech
Строим лучшую PropTech-компанию в России

Как мы перешли с Elastic на Grafana stack и сократили расходы в несколько раз

Reading time8 min
Views29K

Привет! Хочу поделиться историей миграции сервисов логирования и трейсинга с компонентов Elastic Stack на Grafana Stack и тем, что из этого вышло. До миграции у нас в М2 использовались достаточно классические схемы:

  • Logstash → Elasticsearch → Kibana для логов;

  • Jaeger → Elasticsearch → Kibana (Jaeger UI) для трейсов.

Это вполне рабочий вариант, который устраивал нас первые полтора года жизни проекта. Но время шло, микросервисы плодились как грибы после дождя, рос и объем клиентских запросов. Расширение ресурсов систем логирования и трейсинга становилось все более частой задачей. Объемов хранилищ и вычислительных мощностей требовалось все больше. Вдобавок лицезии X-Pack еще сильнее толкали ценник вверх. Когда замаячили проблемы с приобретением лицензий и доступом к самим продуктам компании Elastic, стало понятно, что дальше так жить нельзя.

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

  • Vector → Loki → Grafana;

  • Jaeger → Tempo → Grafana.

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

  • сокращение объема дискового пространства при тех же объемах данных;

  • сокращение объема вычислительных ресурсов для работы системы;

  • отсутствие необходимости покупки лицензии;

  • свободный доступ к продукту;

  • достаточно простая настройка механизма автомасштабирования системы.

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


Предпосылки миграции. Logging

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

В сутки набегало порядка 1 ТБ логов. Кластер состоял примерно из 10 Elasticsearch data-нод, была приобретена лицензия X-Pack (главным образом, для доменной авторизации и алертинга). Приложения в основном были развернуты в кластере Kubernetes. Для их отправки использовался Fluent Bit, далее Kafka в качестве буфера и пул Logstash под каждый namespace. В процессе эксплуатации системы мы сталкивались с различными проблемами: некоторые решались достаточно просто, для части подходил только workaround, а какие-то решить и вовсе не удавалось. Совокупность второй и третьей групп проблем побудила нас к поиску другого решения. Прежде перечислю наиболее значимые из этих проблем.

1. Потери логов при сборе

Как ни странно, первым компонентом, с которым начались проблемы, стал Fluent Bit. Время от времени он просто переставал отправлять логи отдельных подов. Анализ дебаг-логов, тюнинг буферов и обновление версии к желаемому эффекту не приводили. В качестве замены был взят Vector, который, как позже выяснилось, тоже имел подобные проблемы. Но это было исправлено в версии 0.21.0.

2. Костыли с DLQ

Следующей неприятностью стало вынужденное использование костылей при включении DLQ на Logstash. Дело в том, что Logstash не умеет сам ротировать логи, попадающие в эту очередь, и в качестве почти официального workaround предлагалось просто рестартовать инстанс после достижения порогового объема. Негативно на работу системы в целом это не влияло, так как в качестве input использовалась Kafka и сервис завершался в graceful-режиме. Но видеть постоянно растущее число рестартов подов было так себе, да и за рестартами иногда маскировались другие проблемы.

3. Боли с написанием алертов

Не слишком удобное описание правил алертинга. Можно, конечно, накликать через веб-интерфейс Kibana, но удобней все же через описание через код, как, например, в Prometheus. Синтаксис достаточно неочевидный и вырвиглазный, вот пример:

{

 "params":{

   "aggType":"count",

   "termSize":5,

   "thresholdComparator":"<",

   "timeWindowSize":15,

   "timeWindowUnit":"m",

   "groupBy":"all",

   "threshold":[50],

   "timeField":p",

   "index":["app-common*"]

 },

 "consumer":"alerts",

 "schedule":{

   "interval":"5m"

 },

 "tags":[],

 "name":"app-common",

 "enabled":true,

 "throttle":"1h",

 "rule_type_id":".index-threshold",

 "notify_when":"onActionGroupChange",

 "actions":[

   {

     "group":"threshold met",

     "id":"378045c0-2101-11ec-83cd-97f03e582f14",

     "params":{

       "level":"warning",

       "message":"There is low log rate for 15 minutes in {{rule.name}}:\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}"

     }

   }

 ]

}

4. Потребление ресурсов

Но основные проблемы были связаны с увеличением стоимости потребляемых ресурсов и, как следствие, стоимости системы. Когда цена перевалила за полмиллиона в месяц, мы стали все чаще задумываться над поиском альтернатив. Самыми прожорливыми компонентами оказались Logstash и Elasticsearch, ведь JVM, как известно, неравнодушна к количеству памяти. 

5. Доступность продукта

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

Tracing

Для централизованного сбора трейсов использовался Jaeger, который через Kafka отправлял данные в отдельный кластер «Эластика». Трейсов меньше не становилось, и приходилось масштабировать систему под сотни гигабайт трейсов ежедневно. Схема выглядела следующим образом:

Общим неудобством было также использование разных веб-интерфейсов под различные аспекты мониторинга:

  • Grafana — для метрик;

  • Kibana — для логов;

  • Jaeger UI — для трейсов.

Конечно, Grafana позволяет подключить в качестве источника данных и Elasticsearch, и Jaeger, но остается необходимость манипулировать различными синтаксисами запросов к данным.

С таких предпосылок начался наш поиск новых решений для логирования и трейсинга. Не то чтобы мы проводили какой-то сравнительный анализ различных систем. Сейчас на рынке из серьезных продуктов представлены в основном те, что требуют лицензирования, и с этим в любой момент могла возникнуть проблема. Поэтому мы решили взять opensource-проект Grafana Loki, который уже был успешно внедрен в ряде компаний, а затем очередь дошла и до Tempo.

Миграция в Loki

Итак, почему был выбран именно Loki

  • это opensource-продукт, позволяющий реализовать все необходимые нам фичи;

  • компоненты Loki потребляют ощутимо меньше ресурсов при тех же нагрузках;

  • все компоненты могут быть запущены в кластере Kubernetes, можно использовать HPA или Keda для их автоматического масштабирования;

  • данные занимают в несколько раз меньше места, так как хранятся в сжатом виде;

  • построение запросов очень схоже с языком PromQL;

  • описание алертов аналогично алертам в Prometheus;

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

В качестве способа развертывания был выбран Distributed helm-chart, а в качестве хранилища чанков — Object Storage. Logstash был заменен на более легковесный Vector. На небольших объемах (несколько сотен сообщений в секунду) система вполне работоспособна из коробки. Логи успевают сохраняться практически в режиме realtime, поиск свежих данных работает почти также быстро, как и в Kibana. Получившаяся схема выглядит следующим образом:

Тюнинг настроек

С увеличением нагрузки начинает страдать цепочка записи. То ingester, то distributor начинают дропать логи, возвращать таймауты и т. д. А при запросах данных, отсутствующих в кэше ingester-ов, ожидание ответа начинает приближаться к минуте или вовсе падать по таймауту. На всякий случай приведу схему того, как выглядит инсталляция Loki через Distributed chart.

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

limits_config.ingestrion_burst _size_mb
limits_config.rate_mb

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

Для увеличения скорости поиска стоит использовать кэширование в Memcached или Redis. Также можно поиграть с параметрами:

limits.config.split_queries_by_interal
frontend_worker.parallelisim

В Loki может использоваться кэширование четырех типов данных:

  • чанки;

  • индексы;

  • ответы на предыдущие запросы;

  • кэширование данных для нужд дедупликации.

Стоит использовать как минимум первые три.

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

Что касается правил алертинга, пишутся они аналогично правилам Prometheus.

- alert: low_log_rate_common

  expr: sum(count_over_time({namespace="common"}[15m])) < 50

  for: 5m

  labels:

      severity: warning

      annotations:

        summary: Count is less than 50 from {{ $labels.namespace }}. Current VALUE = {{ $value }}

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

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

Миграция в Tempo

Tempo — более молодой продукт (появился в 2020-м), имеющий очень схожую с Loki архитектуру (в целом, как и Mimir). В качестве способа развертывания был выбран Distributed helm-chart.

Дистрибьюторы имеют возможность подключаться к Kafka напрямую, но в таком виде не удалось добиться скорости вычитывания, соразмерной скорости записи. С использованием Grafana agent удалось эту проблему решить.

Тюнинг настроек

В процессе конфигурирования следует уделить внимание следующим моментам:

  1. Если используется Jaeger, то спаны от Grafana agent в Distributor будут отправляться по GRPC. В кластере Kubernetes равномерное распределение по дистрибьюторам потребует настройки балансировщика, например Envoy (как вариант, через Istio).

  2. В случае проблем со скоростью записи стоит увеличить параметры: 

    1. overrides.ingestion_burst_size_bytes

    2. overrides.ingestion_rate_limit_bytes

    3. overrides.max_bytes_per_trace

  3. Также можно увеличить таймаут ожидания ответа от ingester — ingester_client.remote_timeout. Они не всегда успевают ответить за 5 секунд.

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

Заключение

От первичной инсталляции Loki в dev-среде до внедрения на production прошло около двух месяцев. Еще столько же потребовалось для Tempo. 

В итоге получилось:

  • уменьшить стоимость систем примерно примерно в 7 раз;

  • уйти от возможных проблем с лицензией;

  • совместить визуализацию метрик, логов и трейсов в единой системе;

  • организовать алертинг аналогичным Prometheus образом;

  • настроить автомасштабирование системы в зависимости от объема поступающих данных.

Справедливости ради, стоит отметить и то, чего добиться пока не удалось:

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

  • получения агрегированных значений за большой промежуток времени (больше суток), например, подсчет числа лог-сообщений функцией count_over_time;

  • производительности в сохранении спанов как в схеме с Elasticsearch. Пока удалось решить горизонтальным масштабированием и увеличением числа партиций в Kafka.

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

Tags:
Hubs:
Total votes 31: ↑31 and ↓0+31
Comments22

Articles

Information

Website
m2.ru
Registered
Founded
Employees
501–1,000 employees
Location
Россия
Representative
Макс Дмитров