ClickHouse + Graphite: как значително да намалите заетото пространство на дисковете

ClickHouse + Graphite: как значително да намалите заетото пространство на дисковете

Здравейте, habr.

Ако някой експлоатира системата graphite-web и се сблъсква с проблеми с производителността на хранилището whisper (IO, заето дисково пространство), то вероятността да е обърнато внимание на ClickHouse като алтернатива трябва да се стреми към единица. Това предположение предполага, че вече се използва трета страна за приемане на метрики, например carbonwriter или go-carbon.

ClickHouse успешно решава описаните проблеми. Например, след прехвърляне на 2TiB данни от whisper, те се побират в 300GiB. Няма да се спирам подробно на сравнението, тъй като има достатъчно статии по темата. Освен това, до скоро с нашето ClickHouse хранилище не всичко беше идеално.

Проблеми с заетото пространство

На пръв поглед всичко трябва да работи добре. Спазвайки документацията, създаваме конфигурация за схемата на съхранение на метрики (по-нататък retention), след което създаваме таблица в съответствие с препоръките на избрания бекенд за graphite-web: carbon-clickhouse+graphite-clickhouse или graphouse, в зависимост от това какъв стек се използва. И... активира се бомба със забавен таймер.

За да разберем коя, трябва да знаем как работят вставките и по-нататъшния жизнен цикъл на данните в таблиците на двигателите от семейството *MergeTree ClickHouse (схемите са взети от презентацията Алексея Зателепина):

  • Вмъква се блок данни. В нашия случай това са метриките.
    ClickHouse + Graphite: как значително да намалите заетото пространство на дисковете
  • Всеки такъв блок се сортира по ключа CLR потребителска агрегатна функция, посочен при създаването на таблицата.
  • След сортирането, парче (part) данни се записва на диска.
    ClickHouse + Graphite: как значително да намалите заетото пространство на дисковете
  • Сървърът следи на фона, за да не бъде много на брой, и стартира фонови слияния (обединение, по-нататък мержи).
    ClickHouse + Graphite: как значително да намалите заетото пространство на дисковете
    ClickHouse + Graphite: как значително да намалите заетото пространство на дисковете
  • Сървърът спира да стартира мержи самостоятелно, когато данните престават активно да постъпват в партиция (partition), но можем да стартираме процеса ръчно с команда OPTIMIZE.
  • Ако в партицията е останало само едно парче, не може да се стартира мерж с обикновена команда, необходима е OPTIMIZE ... FINAL

И така, постъпват първите метрики. И те заемат определено пространство. Последващите събития могат да варират в зависимост от много фактори:

  • Ключът за партициониране може да бъде както много малък (ден), така и много голям (няколко месеца).
  • Конфигурацията на retention може да включва няколко значителни прага на агрегация на данни вътре в активната партиция (към която се записват метриките), или пък не.
  • Ако данните са много, то най-старите парчета, които поради фоновите обединения могат вече да са огромни (при избор на неоптимален ключ за партизиране), няма да се обединяват сами с новите малки парчета.

И всичко завършва по един и същи начин. Мястото, заето от метриките в ClickHouse, само нараства, ако:

  • не се прилага OPTIMIZE ... FINAL ръчно или
  • не се вкарват данни във всички партиции на постоянно основание, за да се стартира след време фоново обединение.

Вторият метод изглежда най-прост за изпълнение и затова той е неправилен и е бил тестван на първо място.
Написах достатъчно прост скрипт на python, който изпращаше фалшиви метрики за всеки ден през последните 4 години и се пускаше всеки час от cron.
Тъй като цялата работа на ClickHouse DBMS е построена на принципа, че системата в крайна сметка ще свърши цялата фонова работа, но не е известно кога, не успях да изчакам момента, в който старите огромни парчета ще започнат да се обединяват с новите малки. Стана ясно, че трябва да се търси начин за автоматизиране на принудителните оптимизации.

ClickHouse + Graphite: как значително да намалите заетото пространство на дисковете

Информацията в системните таблици на ClickHouse

Нека погледнем структурата на таблицата system.parts. Това е изчерпателна информация за всяко парче от всички таблици на сървъра ClickHouse. Включва, между другото, следните колони:

  • име на БД (database);
  • име на таблицата (table);
  • име и ID на партицията (partition & partition_id);
  • когато парчето е създадено (modification_time);
  • минимална и максимална дата в парчето (партиционирането става по дни) (min_date & max_date);

Има и таблица system.graphite_retentions, със следните интересни полета:

  • име на БД (Tables.database);
  • име на таблицата (Tables.table);
  • възраст на метриката, когато трябва да се приложи следващата агрегация (age);

И така:

  1. Имаме таблица с парчета и таблица с правила за агрегация.
  2. Обединяваме техните пресечни точки и получаваме всички таблици *GraphiteMergeTree.
  3. Търсим всички партиции, в които:
    • повече от едно парче
    • или е настъпил моментът да се приложи следващото правило за агрегация, и modification_time по-стари от този момент.

Реализация

Тази заявка

ИЗБЕРИТЕ
    concat(p.database, '.', p.table) КАК table,
    p.partition_id КАК partition_id,
    p.partition КАК partition,
    -- Найстарейшее "правило", которое можно будет применить к
    -- партиции, но не в будущем, см (*)
    max(g.age) КАК age,
    -- Количество частей в партиции
    countDistinct(p.name) КАК parts,
    -- Для самой старшей метрики в партиции принимается 00:00:00 следующего дня
    toDateTime(max(p.max_date + 1)) КАК max_time,
    -- Когда необходимо оптимизировать партицию
    max_time + age КАК rollup_time,
    -- Когда самый старый кусок в партиции был обновлён
    min(p.modification_time) КАК modified_at
ИЗ system.parts КАК p
INNER JOIN
(
    -- Все правила для всех таблиц *GraphiteMergeTree
    ИЗ system.graphite_retentions
    МАССИВ JOIN Tables
    ГРУППИРОВАТЬ ПО
        database,
        table,
        age
) КАК g ON
    (p.table = g.table)
    И (p.database = g.database)
ГДЕ
    -- Только активные куски
    p.active
    -- (*) И только строки, где правила агрегации уже должны быть применены
    И ((toDateTime(p.max_date + 1) + g.age) < теперь())
ГРУППИРОВАТЬ ПО
    table,
    partition
ИМЕЕТ
    -- Только партиции, которые младше момента оптимизации
    (modified_at  1)
ORDER BY
    table ASC,
    partition ASC,
    age ASC

возвращает каждую из партиций таблиц *GraphiteMergeTree, слияние которых должно привести к освобождению дискового пространства. Осталось только дело за малым: пройтись по всем ним с запросом OPTIMIZE ... FINAL. В конечной реализации также учтён тот момент, что партиции с активной записью трогать не нужно.

Именно это делает проект graphite-ch-optimizer. Бывшие коллеги из Яндекс.Маркет опробовали его в продакшене, результат работы можно увидеть ниже.

ClickHouse + Graphite: как значително да намалите заетото пространство на дисковете

Если запустить программу на сервере с ClickHouse, она просто начнёт работать в режиме демона. Раз в час будет выполняться запрос, проверяя, не появились ли новые партиции старше трёх суток, которые можно оптимизировать.

В ближайших планах — предоставить, по крайней мере, deb пакеты, а по возможности — ещё и rpm.

Вместо заключение

За прошедшие 9 с лишним месяцев я внутри своей компании InnoGames провёл много времени, работая на стыке ClickHouse и graphite-web. Это был хороший опыт, результатом которого стал возможен скорый переход с whisper на ClickHouse в качестве хранилища метрик. Надеюсь, что эта статья станет чем-то вроде начала цикла о том, какие улучшения были внесены нами в различные части этого стека и что будет сделано в будущем.

Няколко литра бира и административни дни бяха вложени в разработването на запитването заедно с v0devil, за което искам да му благодаря. Също така за рецензирането на тази статия.

Страницата на проекта в GitHub

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster