Хабрахабр

Мы два года развивали свою систему мониторинга. Кликай, чтобы…

Всем привет!

После чего мой коллега Сергей Носков писал о самом первом звене нашей системы мониторинга — разработанном нами Bioyino, распределённом масштабируемом агрегаторе метрик. Я уже рассказывал в этом блоге об организации модульной системы мониторинга для микросервисной архитектуры и о переходе с Graphite+Whisper на Graphite+ClickHouse для хранения метрик в условиях высоких нагрузок.

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

Но давайте начнем по порядку.

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

С того момента произошло следующее.

  • 60GHz, 384GB RAM, 10 SSD SAS 745GB, Raid 6, 10GBit/s Net). Количество серверов в кластере Graphite выросло с 3 до 6.
    (56 CPU 2.

  • Правда, после выхода статьи мы подвезли в него поддержку тегов (Graphite) и Raft для выбора лидера. Мы заменили brubeck на bioyino — нашу собственную имплементацию StatsD на Rust, и даже целую статью про это написали.

  • Мы проработали возможность использовать bioyino в качестве StatsD-агента и разместили такие агенты рядом с инстансами монолита, а также там, где это было необходимо в k8s.

  • Мы наконец-то избавились от старой системы мониторинга Munin (формально она у нас ещё есть, но её данные уже нигде не используются).

  • Сбор данных из кластеров Kubernetes был организован через Prometheus/Federations, так как Heapster в новых версиях Kubernetes не поддержали.

За два прошедших года количество принимаемых и обрабатываемых метрик выросло примерно в 9 раз.

Это хорошо видно на графике. Процент занимаемого места на серверах также неумолимо ползёт вверх, и мы предпринимаем различные шаги по его понижению.

Что именно мы делаем?

10 10 10 * * clickhouse-client -q "select distinct partition from system.parts where active=1 and database='graphite' and table='data' and max_date between today()-55 AND today()-35;" | while read PART; do clickhouse-client -u systemXXX --password XXXXXXX -q "OPTIMIZE TABLE graphite.data PARTITION ('"$PART"') FINAL";done

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

Схема Distributed таблицы выглядит следующим образом.

CREATE TABLE graphite.data_all (
`Path` String, `Value` Float64, `Time` UInt32, `Date` Date, `Timestamp` UInt32
) ENGINE = Distributed ( 'graphite_cluster', 'graphite', 'data', jumpConsistentHash(cityHash64(Path), 3)
)

Мы также назначили пользователю "default" readonly-права и перекинули выполнение процедур записи в таблицы на отдельного пользователя systemXXX.

Конфигурация кластера Graphite в ClickHouse выглядит следующим образом.

<remote_servers> <graphite_cluster> <shard> <internal_replication>true</internal_replication> <replica> <host>graphite-clickhouse01</host> <port>9000</port> <user>systemXXX</user> <password>XXXXXX</password> </replica> <replica> <host>graphite-clickhouse04</host> <port>9000</port> <user>systemXXX</user> <password>XXXXXX</password> </replica> </shard> <shard> <internal_replication>true</internal_replication> <replica> <host>graphite-clickhouse02</host> <port>9000</port> <user>systemXXX</user> <password>XXXXXX</password> </replica> <replica> <host>graphite-clickhouse05</host> <port>9000</port> <user>systemXXX</user> <password>XXXXXX</password> </replica> </shard> <shard> <internal_replication>true</internal_replication> <replica> <host>graphite-clickhouse03</host> <port>9000</port> <user>systemXXX</user> <password>XXXXXX</password> </replica> <replica> <host>graphite-clickhouse06</host> <port>9000</port> <user>systemXXX</user> <password>XXXXXX</password> </replica> </shard> </graphite_cluster> </remote_servers>

Эти данные используются для: Помимо нагрузки на запись, выросло количество запросов на чтение данных из Graphite.

  • обработки триггеров и формирования алертов;
  • отображения графиков на мониторах в офисе и экранах ноутбуков и ПК растущего числа сотрудников компании.

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

CREATE TABLE graphite.data_reverse (
`Path` String, `Value` Float64, `Time` UInt32 CODEC(Delta(4), ZSTD(1)), `Date` Date, `Timestamp` UInt32
) ENGINE = ReplicatedGraphiteMergeTree ( '/clickhouse/tables//data_reverse', '{replica}', 'graphite_rollup'
) PARTITION BY Date ORDER BY (Path, Time) SETTINGS index_granularity = 4096

Чтобы направлять в неё данные, мы добавили в конфигурационный файл приложения carbon-clickhouse новую секцию.

[upload.graphite_reverse]
type = "points-reverse"
table = "graphite.data_reverse"
threads = 2
url = "http://systemXXX:XXXXXXX@localhost:8123/"
timeout = "60s"
cache-ttl = "6h0m0s"
zero-timestamp = true

Оно выглядит примерно так. Чтобы удалять партиции старше двух дней, мы написали задание cron.

1 12 * * * clickhouse-client -q "select distinct partition from system.parts where active=1 and database='graphite' and table='data_reverse' and max_date<today()-2;" | while read PART; do clickhouse-client -u systemXXX --password XXXXXXX -q "ALTER TABLE graphite.data_reverse DROP PARTITION ('"$PART"')";done

Чтобы читать из таблицы данные, в конфигурационном файле graphite-clickhouse добавили секцию:

[[data-table]]
table = "graphite.data_reverse"
max-age = "48h"
reverse = true

А также мы имеем шардированную таблицу с 1/3 данных на каждом шарде, обеспечивающую чтение всех исторических данных. В результате мы имеем таблицу с 100% данных, реплицированных на все шесть серверов, которые обрабатывают всю читающую нагрузку от запросов с окном менее двух суток (а таких у нас 95%). И пусть таких запросов кратно меньше, нагрузка от них значительно выше.

В результате роста объемов записываемых и читаемых данных в кластере Graphite, выросла и суммарная CPU-нагрузка на серверы. Что же происходит с CPU?! Выглядит она примерно так.

2 от 2018-09-05, отвечает за транспорт метрик), который размещен на трёх серверах из шести. Хочется обратить внимание на следующий нюанс: половина CPU уходит на парсинг и первичную обработку метрик в carbon-c-realy (v3. Как видно по графику, именно эти три сервера и находятся в ТОПе.

Для гибкого управления триггерами, нотификациями и эскалациями, мы используем декларативное описание, которое назвали alert.yaml. В качестве системы алертинга у нас по-прежнему Moira и написанный под неё moira-client. Для работы с alert.yaml мы сделали обвязку над moira-client и назвали её alert-autoconf (планируем заопенсорсить). Оно генерируется автоматически при создании сервиса через PaaS (подробнее об этом можно почитать в статье Вадима Мадисона «Что мы знаем о микросервисах») и размещается в его репозитории. При коммите изменений в alert.yaml запускаются автотесты, которые проверяют валидность yaml-файла, а также делают запросы в Graphite по каждому шаблону метрик с целью проверить их корректность. В сборке сервиса в TeamCity есть шаг с экспортом триггеров и нотификаций в Moira через alert-autoconf.

В нем сделали структуру вида: Команда/Проект/alert.yaml. Для инфраструктурных команд, не использующих PaaS, мы организовали отдельный репозиторий под названием Alerting. К каждому alert.yaml мы генерируем отдельную сборку в TeamCity, которая прогоняет тесты и пушит содержимое alert.yaml в Moira.

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

Содержимое полученного yaml-документа можно вставить в alert.yaml практически без дополнительных преобразований, после чего запушить изменения в мастер. Так как раньше у нас уже были триггеры, заведённые через GUI, мы реализовали возможность выгрузить их в формате yaml. В ходе сборки alert-autoconf поймет, что такой триггер уже существует и зарегистрирует его в нашем реестре в Redis.

Для того, чтобы передать триггеры им на обслуживание, достаточно в своем alert.yaml корректно заполнить описание «что делать, если ты это видишь», поставить тег [24x7] и запушить изменения в мастер. А ещё не так давно мы обзавелись дежурной сменой инженеров 24х7. У — Упрощай! После раскатки alert.yaml'а все описанные в нем триггеры автоматически попадут под круглосуточное наблюдение смены 24х7. Красота!

С момента выхода прошлой статьи про сбор и обработку бизнес-метрик наш bioyino стал ещё лучше.

  1. Вместо выбора лидера через Consul используется встроенный Raft.
  2. Корректно обрабатываются теги в формате Graphite.
  3. Появилась возможность использовать bioyino (StatsD-server) в качестве агента.
  4. Для подсчета уникальных значений поддерживается формат "set".
  5. Финальную агрегацию метрик можно делать в несколько потоков.
  6. Данные можно отправлять в Graphite чанками в несколько параллельных соединений.
  7. Исправлены все найденные баги.

Сейчас это работает так.

д.
Statsd-агент размещается рядом с приложением. Мы стали активно внедрять StatsD-агенты рядом со всеми крупными крупными генераторами метрик: в контейнерах с инстансами монолита, в подах k8s рядом с сервисами, на хостах с инфраструктурными компонентами и т. Все события предагрегируются, и собранные данные ежесекундно (интервал можно настроить) отправляются в основной кластер серверов StatsD (bioyino0[1-3]) в формате Cap’n Proto. Он принимает метрики от этого приложения всё так же по UDP, но уже не используя сетевую подсистему (за счёт оптимизаций в ядре Linux).

Про это вы можете подробно прочитать в нашей прошлой статье. Дальнейшая обработка и агрегация метрик, выбор лидера в StatsD-кластере и отправка лидером метрик в Graphite практически не изменились.

Что же касается цифр, то они следующие.

График полученных StatsD-событий

График метрик, отправленных из StatsD в Graphite

Общая схема взаимодействия компонентов мониторинга на данный момент выглядит так.

Суммарное количество значений метрик: 2 189 484 898 474.
Общая глубина хранения метрик: 3 года.
Количество уникальных имен метрик: 6 585 413 171.
Количество триггеров: 1053, они обслуживают от 1 до 15k метрик.

Планы на ближайшее будущее:

  • начать переводить продуктовые сервисы на тегированную схему хранения метрик;
  • добавить в кластер Graphite еще три сервера;
  • подружить Moira с персистентной тканью;
  • найти ещё одного разработчика в команду мониторинга.

А ещё я буду выступать 7 ноября на Highload++, если будете там, можем пообщаться. Буду рад комментариям и вопросам здесь — пишите.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть