Hilsen, habr.
Hvis noen utnytter systemet
ClickHouse løser de beskrevne problemene godt. For eksempel, etter å ha overført 2TiB med data fra whisper, passer de inn i 300GiB. Jeg vil ikke dvele ved sammenligningen i detalj; det er mange artikler om dette emnet. I tillegg, inntil nylig, var ikke alt perfekt med vår ClickHouse-lagring.
Problemer med forbrukt plass
Ved første øyekast skal alt fungere bra. Følgende retention
), lag deretter en tabell i henhold til anbefalingen fra den valgte backend for graphite-web:
For å forstå hvilken, må du vite hvordan innsatser fungerer og den videre livsveien til data i tabeller over motorer i *-familienMergeTree ClickHouse (diagrammer hentet fra
- Innsatt
блок
data. I vårt tilfelle var det beregningene som kom.
- Hver slik blokk sorteres i henhold til nøkkelen før den skrives til disk.
ORDER BY
spesifisert når du oppretter tabellen. - Etter sortering,
кусок
(part
) data skrives til disk.
- Serveren overvåker i bakgrunnen slik at det ikke er mange slike biter, og starter bakgrunnen
слияния
(merge
, heretter sammenslåing).
- Serveren slutter å kjøre sammenslåinger av seg selv så snart data slutter å strømme aktivt inn i
партицию
(partition
), men du kan starte prosessen manuelt med kommandoenOPTIMIZE
. - Hvis det bare er ett stykke igjen i partisjonen, vil du ikke kunne kjøre sammenslåingen med den vanlige kommandoen; du må bruke
OPTIMIZE ... FINAL
Så de første beregningene kommer. Og de tar litt plass. Påfølgende hendelser kan variere noe avhengig av mange faktorer:
- Partisjoneringsnøkkelen kan enten være veldig liten (en dag) eller veldig stor (flere måneder).
- Oppbevaringskonfigurasjonen kan passe til flere betydelige dataaggregeringsterskler innenfor den aktive partisjonen (hvor beregninger er registrert), eller kanskje ikke.
- Hvis det er mye data, vil ikke de tidligste bitene, som på grunn av bakgrunnssammenslåing allerede er enorme (hvis du velger en ikke-optimal partisjoneringsnøkkel), slå seg sammen med ferske små biter.
Og det ender alltid likt. Plassen okkupert av beregninger i ClickHouse øker bare hvis:
- gjelder ikke
OPTIMIZE ... FINAL
manuelt eller - ikke legg inn data i alle partisjoner fortløpende, slik at en bakgrunnssammenslåing før eller siden starter
Den andre metoden ser ut til å være den enkleste å implementere, og derfor er den feil og ble prøvd først.
Jeg skrev et ganske enkelt python-skript som sendte dummy-beregninger for hver dag de siste 4 årene og kjørte cron hver time.
Siden hele driften av ClickHouse DBMS er basert på det faktum at dette systemet før eller siden vil gjøre alt bakgrunnsarbeidet, men det er ikke kjent når, klarte jeg ikke å vente på øyeblikket da de gamle enorme stykkene verdig seg til å begynne å slå seg sammen med nye små. Det ble klart at vi måtte se etter en måte å automatisere tvungne optimaliseringer.
Informasjon i ClickHouse systemtabeller
La oss ta en titt på tabellstrukturen
- db navn (
database
); - tabellnavn (
table
); - partisjonsnavn og ID (
partition
&partition_id
); - når stykket ble opprettet (
modification_time
); - minimum og maksimum dato i et stykke (partisjonering gjøres etter dag) (
min_date
&max_date
);
Det er også et bord
- db navn (
Tables.database
); - tabellnavn (
Tables.table
); - metrisk alder når neste aggregering skal brukes (
age
);
Så:
- Vi har en tabell med biter og en tabell med aggregeringsregler.
- Vi kombinerer skjæringspunktet deres og får alle tabellene *GraphiteMergeTree.
- Vi ser etter alle partisjoner hvor:
- mer enn ett stykke
- eller tiden er inne for å bruke neste aggregeringsregel, og
modification_time
eldre enn dette øyeblikket.
implementering
Denne forespørselen
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
returnerer hver av *GraphiteMergeTree-tabellpartisjonene hvis sammenslåing skal frigjøre diskplass. Det eneste som gjenstår er å gå gjennom dem alle med en forespørsel OPTIMIZE ... FINAL
. Den endelige implementeringen tar også hensyn til det faktum at det ikke er behov for å berøre partisjoner med aktivt opptak.
Det er nettopp dette prosjektet gjør
Hvis du kjører programmet på en server med ClickHouse, vil det ganske enkelt begynne å fungere i daemon-modus. En gang i timen vil en forespørsel bli utført, som sjekker om det har dukket opp nye partisjoner eldre enn tre dager som kan optimaliseres.
Våre umiddelbare planer er å gi minst deb-pakker, og om mulig også rpm.
I stedet for en konklusjon
I løpet av de siste 9+ månedene har jeg vært inne i selskapet mitt
Det ble brukt flere liter øl og admindager på å utvikle forespørselen, sammen med
Kilde: www.habr.com