Поздрав хабр.
Ако неко експлоатише систем
ЦлицкХоусе добро решава описане проблеме. На пример, након преноса 2ТиБ података из шапата, они се уклапају у 300ГиБ. Нећу се задржавати на поређењу у детаље; има доста чланака на ову тему. Поред тога, донедавно није све било савршено са нашим ЦлицкХоусе складиштем.
Проблеми са заузетим простором
На први поглед, све би требало да функционише добро. Следећи retention
), а затим креирајте табелу према препоруци изабраног бацкенд-а за грапхите-веб:
Да бисте разумели који, морате знати како функционишу уметци и даљи животни пут података у табелама мотора породице *МергеТрее ЦлицкХоусе (графикони преузети из
- Umetnuto
блок
података. У нашем случају, метрика је стигла.
- Сваки такав блок се сортира према кључу пре него што се упише на диск.
ORDER BY
наведен при креирању табеле. - Након сортирања,
кусок
(part
) подаци се уписују на диск.
- Сервер прати у позадини да нема много таквих комада и покреће позадину
слияния
(merge
, у даљем тексту спајање).
- Сервер престаје да ради обједињавање сам од себе чим подаци престану да активно тече у
партицию
(partition
), али можете ручно покренути процес помоћу командеOPTIMIZE
. - Ако је у партицији остао само један комад, тада нећете моћи да покренете спајање користећи уобичајену команду; морате користити
OPTIMIZE ... FINAL
Дакле, стижу прве метрике. И заузимају мало простора. Накнадни догађаји могу донекле варирати у зависности од многих фактора:
- Кључ за партиционисање може бити или веома мали (један дан) или веома велики (неколико месеци).
- Конфигурација задржавања може да одговара неколико значајних прагова агрегације података унутар активне партиције (где се бележе метрике), а можда и не.
- Ако има много података, онда се најранији делови, који због спајања у позадини могу већ бити огромни (ако одаберете неоптималан кључ за партиционисање), неће спојити сами себе са свежим малим комадима.
И увек се исто заврши. Простор који заузимају метрика у ЦлицкХоусе-у се повећава само ако:
- не примјењују
OPTIMIZE ... FINAL
ручно или - немојте стално убацивати податке у све партиције, да би пре или касније почело спајање у позадини
Чини се да је други метод најлакши за имплементацију и стога је нетачан и први је испробан.
Написао сам прилично једноставну Питхон скрипту која је слала лажне метрике за сваки дан у протекле 4 године и покретала црон сваки сат.
Пошто се цео рад ЦлицкХоусе ДБМС заснива на чињеници да ће овај систем пре или касније обавити све позадинске послове, али се не зна када, нисам могао да дочекам тренутак када се стари огромни комади удостоје да почну да се спајају. нове мале. Постало је јасно да морамо тражити начин да аутоматизујемо принудне оптимизације.
Информације у системским табелама ЦлицкХоусе
Хајде да погледамо структуру табеле
- дб име (
database
); - име табеле (
table
); - име и ИД партиције (
partition
&partition_id
); - када је комад настао (
modification_time
); - минимални и максимални датум у комаду (подела се врши по дану) (
min_date
&max_date
);
Ту је и сто
- дб име (
Tables.database
); - име табеле (
Tables.table
); - метрички узраст када треба применити следећу агрегацију (
age
);
Дакле:
- Имамо табелу делова и табелу правила агрегације.
- Комбинујемо њихов пресек и добијамо све табеле *ГрапхитеМергеТрее.
- Тражимо све партиције у којима:
- више од једног комада
- или је дошло време да се примени следеће правило агрегације, и
modification_time
старији од овог тренутка.
Имплементација
Овај захтев
SELECT
concat(p.database, '.', p.table) AS table,
p.partition_id AS partition_id,
p.partition AS partition,
-- Самое "старое" правило, которое может быть применено для
-- партиции, но не в будущем, см (*)
max(g.age) AS age,
-- Количество кусков в партиции
countDistinct(p.name) AS parts,
-- За самую старшую метрику в партиции принимается 00:00:00 следующего дня
toDateTime(max(p.max_date + 1)) AS max_time,
-- Когда партиция должна быть оптимизированна
max_time + age AS rollup_time,
-- Когда самый старый кусок в партиции был обновлён
min(p.modification_time) AS modified_at
FROM system.parts AS p
INNER JOIN
(
-- Все правила для всех таблиц *GraphiteMergeTree
SELECT
Tables.database AS database,
Tables.table AS table,
age
FROM system.graphite_retentions
ARRAY JOIN Tables
GROUP BY
database,
table,
age
) AS g ON
(p.table = g.table)
AND (p.database = g.database)
WHERE
-- Только активные куски
p.active
-- (*) И только строки, где правила аггрегации уже должны быть применены
AND ((toDateTime(p.max_date + 1) + g.age) < now())
GROUP BY
table,
partition
HAVING
-- Только партиции, которые младше момента оптимизации
(modified_at < rollup_time)
-- Или с несколькими кусками
OR (parts > 1)
ORDER BY
table ASC,
partition ASC,
age ASC
враћа сваку партицију табеле *ГрапхитеМергеТрее чије би спајање требало да ослободи простор на диску. Остаје само да их све прођете са захтевом OPTIMIZE ... FINAL
. Коначна имплементација такође узима у обзир чињеницу да нема потребе додиривати партиције са активним снимањем.
То је управо оно што пројекат ради
Ако покренете програм на серверу са ЦлицкХоусе, он ће једноставно почети да ради у демонском режиму. Једном на сат ће се извршавати захтев који проверава да ли су се појавиле нове партиције старије од три дана које се могу оптимизовати.
Наши непосредни планови су да обезбедимо барем деб пакете, а ако је могуће и рпм.
Уместо закључка
Током протеклих 9+ месеци био сам у својој компанији
Неколико литара пива и админ дана потрошено је на израду захтева, заједно са
Извор: ввв.хабр.цом