Üdvözlet, habr.
Ha valaki kihasználja a rendszert
A ClickHouse jól megoldja a leírt problémákat. Például 2 TiB adat átvitele után a whisperből 300 GiB-be férnek bele. Nem foglalkozom részletesen az összehasonlítással, rengeteg cikk van ebben a témában. Ráadásul egészen a közelmúltig nem volt minden tökéletes a ClickHouse tárolónkkal.
Problémák az elhasznált hellyel
Első pillantásra mindennek jól kell működnie. Következő retention
), majd hozzon létre egy táblázatot a grafit-web kiválasztott háttérprogramjának ajánlása szerint:
Annak megértéséhez, hogy melyik, ismernie kell a betétek működését és az adatok további életútját a * család motorjainak táblázataibanMergeTree ClickHouse (diagramok származnak
- Beszúrva
блок
adat. Esetünkben a mérőszámok érkeztek.
- Minden ilyen blokkot a kulcs szerint rendeznek, mielőtt lemezre írnák.
ORDER BY
táblázat létrehozásakor megadva. - A válogatás után,
кусок
(part
) az adatok lemezre kerülnek.
- A szerver a háttérben figyel, hogy ne legyen sok ilyen darab, és elindítja a hátteret
слияния
(merge
, a továbbiakban összevonás).
- A kiszolgáló magától leállítja az egyesítések futtatását, amint leáll az adatok aktív áramlása a
партицию
(partition
), de a folyamatot manuálisan is elindíthatja a paranccsalOPTIMIZE
. - Ha csak egy darab maradt a partícióban, akkor nem tudja futtatni az egyesítést a szokásos paranccsal;
OPTIMIZE ... FINAL
Tehát megérkeznek az első mutatók. És elfoglalnak egy kis helyet. A későbbi események némileg változhatnak számos tényezőtől függően:
- A particionáló kulcs lehet nagyon kicsi (egy nap) vagy nagyon nagy (több hónap).
- A megőrzési konfiguráció több jelentős adatösszesítési küszöböt is illeszthet az aktív partíción belül (ahol a mérőszámok rögzítve vannak), vagy nem.
- Ha sok az adat, akkor a legkorábbi darabok, amelyek a háttér-összevonás miatt már hatalmasak lehetnek (ha nem optimális particionáló kulcsot választunk), nem egyesülnek friss kis darabokkal.
És mindig ugyanaz a vége. A mérőszámok által elfoglalt hely a ClickHouse-ban csak akkor növekszik, ha:
- ne alkalmazza
OPTIMIZE ... FINAL
manuálisan ill - ne helyezzen be folyamatosan adatokat minden partícióba, így előbb-utóbb megindul a háttér-összevonás
A második módszer tűnik a legkönnyebben megvalósíthatónak, ezért helytelen, és először próbálták ki.
Írtam egy meglehetősen egyszerű python-szkriptet, amely az elmúlt 4 évben minden napra dummy metrikákat küldött, és óránként lefuttatta a cront.
Mivel a ClickHouse DBMS teljes működése azon alapszik, hogy ez a rendszer előbb-utóbb elvégzi az összes háttérmunkát, de nem tudni, hogy mikor, alig vártam a pillanatot, amikor a régi hatalmas darabok méltók egybeolvadni. új kicsiket. Világossá vált, hogy módot kell keresnünk a kényszeroptimalizálások automatizálására.
Információk a ClickHouse rendszertáblázatokban
Vessünk egy pillantást a táblázat szerkezetére
- db név (
database
); - táblázat neve (
table
); - partíció neve és azonosítója (
partition
&partition_id
); - amikor a darab készült (
modification_time
); - minimális és maximális dátum egy darabban (a particionálás naponként történik) (
min_date
&max_date
);
Asztal is van
- db név (
Tables.database
); - táblázat neve (
Tables.table
); - metrikus életkor, amikor a következő összesítést kell alkalmazni (
age
);
Tehát:
- Van egy darab táblázatunk és egy táblázat az összesítési szabályokról.
- Összevonjuk a metszéspontjukat, és megkapjuk az összes táblát *GraphiteMergeTree.
- Minden olyan partíciót keresünk, amelyben:
- több mint egy darab
- vagy eljött az ideje a következő összesítési szabály alkalmazásának, és
modification_time
régebbi ennél a pillanatnál.
Реализация
Ez a kérés
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
visszaadja a *GraphiteMergeTree táblapartíciók mindegyikét, amelyek összevonása lemezterületet szabadít fel. Már csak egy kéréssel kell végigmenni mindegyiken OPTIMIZE ... FINAL
. A végső megvalósítás azt is figyelembe veszi, hogy az aktív rögzítéssel nem kell partíciókat érinteni.
A projekt pontosan ezt teszi
Ha a programot ClickHouse-szal futtatja egy szerveren, akkor egyszerűen démon módban kezd működni. Óránként egyszer végrehajtásra kerül egy kérés, amely ellenőrzi, hogy megjelentek-e új, három napnál régebbi, optimalizálható partíciók.
Közelebbi terveink között szerepel legalább deb csomagok biztosítása, és ha lehet, rpm is.
Ahelyett, hogy egy következtetés
Az elmúlt 9+ hónapban a cégemben dolgoztam
Több liter sör és admin napok teltek el a kérés kidolgozásával együtt
Forrás: will.com