
Salve, habr.
Se qualcuno utilizza il sistema e ha riscontrato problemi di prestazioni dello storage (I/O, spazio su disco consumato), allora la possibilità che sia stata presa in considerazione ClickHouse come sostituto dovrebbe tendere all'unità. Questa affermazione implica che un'implementazione di terze parti è già utilizzata come demone ricevuto delle metriche, ad esempio o .
ClickHouse risolve bene i problemi descritti. Ad esempio, dopo aver trasferito 2TiB di dati da whisper, sono stati ridotti a 300GiB. Non mi soffermerò sul confronto, ci sono abbastanza articoli su questo argomento. Inoltre, fino a poco tempo fa, il nostro storage ClickHouse non era perfetto.
Problemi con lo spazio consumato
A prima vista, tutto dovrebbe funzionare bene. Seguendo , creiamo la configurazione per lo schema di archiviazione delle metriche (in seguito retention), quindi creiamo una tabella secondo le raccomandazioni del backend scelto per graphite-web: + o , a seconda dello stack utilizzato. E… si attiva una bomba a orologeria.
Per capire quale sia, bisogna sapere come funzionano le inserzioni e il ciclo di vita dei dati nelle tabelle dei motori della famiglia *MergeTree ClickHouse (diagrammi estratti da Aleksej Zatelepin):
- Viene inserito
un bloccodi dati. Nel nostro caso, sono arrivate le metriche.

- Ogni blocco di questo tipo viene ordinato in base alla chiave
ORDER BY, specificata al momento della creazione della tabella. - Dopo l'ordinamento,
un pezzo(part) di dati viene scritto su disco.

- Il server monitora in background, per assicurarsi che non ci siano troppi pezzi, e avvia fusioni in background
, quindi merging).(mergeIl server smette di avviare fusioni autonomamente, non appena i dati smettono di arrivare attivamente nella


- partizione
partition(), ma è possibile avviare il processo manualmente con il comandoOPTIMIZESe nella partizione è rimasto solo un pezzo, non si può avviare la fusione con il comando normale, è necessario utilizzare. - OPTIMIZE ... FINAL
E così, arrivano le prime metriche. E occupano uno spazio.
Gli eventi successivi possono variare a seconda di molti fattori:
- La chiave di partizionamento può essere sia molto piccola (un giorno) sia molto grande (alcuni mesi).
- La configurazione di retention può contenere più soglie di aggregazione dei dati all'interno della partizione attiva (dove vengono scritti i metrici), oppure no.
- Se ci sono molti dati, i pezzi più antichi, che a causa delle fusioni in background potrebbero essere già enormi (se viene scelto un chiave di partizionamento non ottimale), non si fonderanno mai con i nuovi pezzi piccoli.
E alla fine finisce sempre allo stesso modo. Lo spazio occupato dai metrici in ClickHouse cresce solo se:
- non si applica
E così, arrivano le prime metriche. E occupano uno spazio.manualmente oppure - non si inseriscono dati in tutte le partizioni su base continua, per avviare prima o poi una fusione in background.
Il secondo modo sembra il più semplice da implementare e, quindi, è sbagliato ed è stato testato per primo.
Ho scritto uno script piuttosto semplice in python, che inviava metriche fittizie per ogni giorno degli ultimi 4 anni e veniva eseguito ogni ora tramite cron.
Poiché tutto il lavoro di ClickHouse DBMS si basa sul fatto che questo sistema prima o poi farà tutto il lavoro in background, ma non si sa quando, non sono stato in grado di aspettare il momento in cui i vecchi grandi pezzi si degnassero di iniziare a fondersi con i nuovi pezzi piccoli. È diventato chiaro che era necessario trovare un modo per automatizzare le ottimizzazioni forzate.

Informazioni nelle tabelle di sistema di ClickHouse
Diamo un'occhiata alla struttura della tabella . Queste sono informazioni complete su ogni pezzo di tutte le tabelle sul server ClickHouse. Contiene, tra l'altro, le seguenti colonne:
- nome del database (
database); - nome della tabella (
table); - nome e ID della partizione (
), ma è possibile avviare il processo manualmente con il comando&partition_id); - quando è stato creato il pezzo (
modification_time); - data minima e massima nel pezzo (la partizione avviene per giorno) (
min_date&max_date);
C'è anche la tabella , con i seguenti campi interessanti:
- nome del database (
Tables.database); - nome della tabella (
Tables.table); - età del metric, quando deve essere applicata la successiva aggregazione (
age);
Ecco:
- Abbiamo una tabella dei pezzi e una tabella delle regole di aggregazione.
- Uniamo la loro intersezione e otteniamo tutte le tabelle *GraphiteMergeTree.
- Cerchiamo tutte le partizioni in cui:
- c'è più di un pezzo
- oppure è giunto il momento di applicare la seguente regola di aggregazione, e
modification_timeè piùvecchio di questo momento.
Implementazione
Questa richiesta
SELEZIONA
concat(p.database, '.', p.table) AS tabella,
p.partition_id AS partition_id,
p.partition AS partizione,
-- La "regola" più "antica" che può essere applicata a
-- una partizione, ma non in futuro, vedi (*)
max(g.age) AS età,
-- Numero di pezzi nella partizione
countDistinct(p.name) AS parti,
-- La metrica più vecchia nella partizione è considerata 00:00:00 del giorno successivo
toDateTime(max(p.max_date + 1)) AS max_time,
-- Quando la partizione deve essere ottimizzata
max_time + età AS rollup_time,
-- Quando il pezzo più vecchio nella partizione è stato aggiornato
min(p.modification_time) AS modificato_il
DA system.parts AS p
INNER JOIN
(
-- Tutte le regole per tutte le tabelle *GraphiteMergeTree
SELEZIONA
Tables.database AS database,
Tables.table AS tabella,
età
DA system.graphite_retentions
ARRAY JOIN Tables
GROUP BY
database,
tabella,
età
) AS g ON
(p.table = g.table)
E (p.database = g.database)
DOVE
-- Solo pezzi attivi
p.active
-- (*) E solo righe in cui le regole di aggregazione devono già essere state applicate
E ((toDateTime(p.max_date + 1) + g.age) < now())
GROUP BY
tabella,
partizione
HAVING
-- Solo partizioni più giovani del momento di ottimizzazione
(modificato_il 1)
ORDINA PER
tabella ASC,
partizione ASC,
età ASCrestituisce ciascuna delle partizioni delle tabelle *GraphiteMergeTree, la cui fusione dovrebbe portare al recupero di spazio su disco. Resta solo da fare una cosa: eseguire una query su di esse. E così, arrivano le prime metriche. E occupano uno spazio.. Nella realizzazione finale è stato considerato anche il fatto che non è necessario toccare le partizioni con scrittura attiva.
È proprio questo che fa il progetto . I precedenti colleghi di Yandex.Market lo hanno testato in produzione, il risultato del lavoro è visibile qui sotto.

Se si avvia il programma su un server con ClickHouse, questo inizierà a funzionare in modalità demone. Una volta all'ora verrà eseguita una query per controllare se sono apparse nuove partizioni più vecchie di tre giorni che possono essere ottimizzate.
Nei prossimi piani c'è l'intenzione di fornire, almeno, pacchetti deb e, se possibile, anche rpm.
In conclusione
Negli oltre 9 mesi trascorsi, ho trascorso molto tempo all'interno della mia azienda nel confronto tra ClickHouse e graphite-web. È stata una buona esperienza, il risultato della quale ha reso possibile un rapido passaggio da whisper a ClickHouse come archivio per le metriche. Spero che questo articolo sia una sorta di inizio di un ciclo su quali miglioramenti sono stati apportati da noi in diverse parti di questo stack e cosa sarà fatto in futuro.
Per lo sviluppo della richiesta sono stati spesi diversi litri di birra e giorni di lavoro insieme a , per cui desidero esprimergli la mia gratitudine. E anche per la revisione di questo articolo.
Fonte: habr.com




