Zabbix è un sistema di monitoraggio. Come qualsiasi altro sistema, affronta tre problemi principali comuni a tutti i sistemi di monitoraggio: raccolta e elaborazione dei dati, archiviazione della cronologia e la sua pulizia.
Le fasi di acquisizione, elaborazione e registrazione dei dati richiedono tempo. Poco, ma per un sistema di grandi dimensioni questo può tradursi in ritardi significativi. Il problema dell'archiviazione riguarda l'accesso ai dati, che vengono utilizzati per report, verifiche e trigger. I ritardi nell'accesso ai dati incidono anche sulle prestazioni. Man mano che i database crescono, è necessario rimuovere i dati obsoleti. La cancellazione è un'operazione pesante che consuma anche parte delle risorse.

I problemi di latenza nella raccolta e nell'archiviazione in Zabbix vengono risolti tramite caching: diversi tipi di cache, caching nel database. Per affrontare il terzo problema, il caching non è adatto, quindi in Zabbix è stato adottato TimescaleDB. Ne parlerà Andrej Guščin — ingegnere del supporto tecnico . Andrej lavora nel supporto di Zabbix da oltre 6 anni e si confronta direttamente con le prestazioni.
Come funziona TimescaleDB e quali prestazioni può offrire rispetto a un tradizionale PostgreSQL? Qual è il ruolo di Zabbix per il database TimescaleDB? Come avviare da zero e come migrare da PostgreSQL, e quale configurazione offre le migliori prestazioni? Di tutto ciò parleremo nel seguito.

Sfide delle prestazioni
Ogni sistema di monitoraggio affronta determinate sfide in termini di prestazioni. Parlerò di tre di esse: raccolta e trattamento dei dati, archiviazione, pulizia della storia.
Raccolta e trattamento dei dati rapidi. Un buon sistema di monitoraggio deve ricevere rapidamente tutti i dati e trattarli secondo le espressioni di attivazione, in base ai propri criteri. Dopo il trattamento, il sistema deve anche salvare rapidamente questi dati nel database per un utilizzo successivo.
Archiviazione della storia. Un buon sistema di monitoraggio deve conservare la cronologia nel database e fornire un facile accesso alle metriche. La cronologia è necessaria per utilizzarla in report, grafici, attivazioni, soglie e elementi di dati calcolati per le notifiche.
Pulizia della storia. A volte arriva il giorno in cui non hai più bisogno di conservare le metriche. Perché mai dovresti avere dati raccolti cinque anni fa, un mese o due fa: alcuni nodi sono stati rimossi, alcuni host o metriche non sono più necessari perché obsoleti e non vengono più raccolti. Un buon sistema di monitoraggio dovrebbe conservare i dati storici e periodicamente rimuoverli per evitare che il database cresca eccessivamente.
La pulizia dei dati obsoleti è una questione cruciale che influisce notevolmente sulle prestazioni del database.
Caching in Zabbix
In Zabbix, la prima e la seconda chiamata vengono gestite tramite caching. Per la raccolta e l'elaborazione dei dati viene utilizzata la memoria RAM. Per lo storage — la storia nei trigger, nei grafici e negli elementi di dati calcolati. Lato database, c'è un certo caching per le query principali, ad esempio per i grafici.
Il caching sul server Zabbix è:
- ConfigurationCache;
- ValueCache;
- HistoryCache;
- TrendsCache.
Esaminiamoli in dettaglio.
ConfigurationCache
Questo è il caching principale in cui conserviamo metriche, host, elementi di dati, trigger — tutto ciò che è necessario per il PreProcessing e per la raccolta dei dati.

Tutto ciò è memorizzato in ConfigurationCache, per evitare richieste superflue al database. Dopo l'avvio del server, aggiorniamo questa cache, creiamo e aggiorniamo periodicamente le configurazioni.
Raccolta dati
Lo schema è abbastanza grande, ma l'aspetto principale è raccoltori. Si tratta di vari «poller» — processi di raccolta. Si occupano di diversi tipi di raccolta: raccolgono dati tramite SNMP, IPMI, e trasferiscono tutto su PreProcessing.
I raccoglitori sono evidenziati da una linea arancione.
In Zabbix ci sono elementi di dati aggregati calcolati, necessari per aggregare le verifiche. Se abbiamo questi elementi, otteniamo i dati direttamente da ValueCache.
PreProcessing HistoryCache
Tutti i raccoglitori utilizzano ConfigurationCache per ricevere i compiti. Successivamente, li trasferiscono a PreProcessing.

PreProcessing utilizza ConfigurationCache per ricevere i passaggi di PreProcessing. Elabora questi dati in vari modi.
Dopo aver elaborato i dati tramite PreProcessing, li salviamo in HistoryCache per un successivo trattamento. A questo punto si conclude la raccolta dei dati e procediamo al processo principale in Zabbix — history syncer, dato che si tratta di un'architettura monolitica.
Nota: il PreProcessing è un'operazione piuttosto pesante. Con la versione 4.2 è stato spostato sul proxy. Se avete un Zabbix molto grande con un alto numero di elementi dati e una frequenza di raccolta elevata, questo semplifica notevolmente il lavoro.
ValueCache, cache storica e di tendenze
Il History syncer è il processo principale che elabora in modo atomico ogni elemento dati, vale a dire ogni valore.
Il History syncer preleva i valori dalla HistoryCache e verifica nel Configuration la presenza di trigger per i calcoli. Se presenti, esegue i calcoli.
Il History syncer genera un evento, un'escalation per creare avvisi, se richiesto dalla configurazione, e registra. Se ci sono trigger per una successiva elaborazione, memorizza quel valore nel ValueCache, in modo da non dover accedere alla tabella storica. In questo modo, il ValueCache si riempie di dati necessari per il calcolo dei trigger e degli elementi calcolati.
Il History syncer scrive tutti i dati nel DB, e il DB su disco. Il processo di elaborazione si conclude qui.

Caching nel DB
Dallato del DB ci sono vari cache quando si desidera visualizzare grafici o report sugli eventi:
Innodb_buffer_poollato MySQL;shared_bufferslato PostgreSQL;effective_cache_sizelato Oracle;shared_poollato DB2.
Ci sono molti altri cache, ma questi sono i principali per tutti i DB. Permettono di mantenere in memoria i dati che sono frequentemente necessari per le query. Ciascuno di essi ha la propria tecnologia per questo.
Le prestazioni del DB sono cruciali.
Il server Zabbix raccoglie continuamente dati e li registra. Al riavvio, legge anche dalla cronologia per popolare il ValueCache. Utilizza script e report. Zabbix API, che è costruito sulla base dell'interfaccia web. L'API di Zabbix accede al database e ottiene i dati necessari per grafici, report, elenchi eventi e problemi recenti.

Per la visualizzazione — Grafana. Tra i nostri utenti, questa è una soluzione popolare. È in grado di inviare direttamente richieste sia attraverso l'API di Zabbix che al DB, creando una certa concorrenza per ottenere dati. Pertanto, è necessaria una configurazione più fine e migliore del DB per garantire una rapida fornitura di risultati e test.
Housekeeper
La terza sfida delle prestazioni in Zabbix è la pulizia della cronologia tramite Housekeeper. Questo rispetta tutte le impostazioni: negli elementi dei dati è indicato per quanti giorni mantenere la dinamica delle variazioni (trend).
TrendsCache calcola i dati al volo. Quando arrivano le informazioni, le aggrega in un'ora e le registra nelle tabelle per monitorare le variazioni delle tendenze.
Housekeeper viene eseguito e rimuove le informazioni dal database con normali 'select'. Questo non è sempre efficiente, come si può vedere dai grafici delle prestazioni dei processi interni.

Il grafico rosso mostra che il History syncer è costantemente occupato. Il grafico arancione sopra è Housekeeper, che viene avviato di continuo. Attende che il database elimini tutte le righe che ha indicato.
Quando è opportuno disattivare Housekeeper? Ad esempio, se ci sono 'Item ID' e si devono rimuovere le ultime 5.000 righe in un determinato intervallo di tempo. Certamente, questo avviene tramite gli indici. Tuttavia, di solito il dataset è molto grande, e il database legge comunque dal disco e carica in cache. Questo è sempre un'operazione molto costosa per il database e, a seconda delle dimensioni, può causare problemi di prestazioni.

È sufficiente disattivare Housekeeper. Nell'interfaccia web c'è un'impostazione in 'Amministrazione generale' per Housekeeper. Disattiviamo il mantenimento interno per la cronologia interna delle tendenze e non gestisce più questa parte.
Le pulizie sono state disattivate, i grafici si sono allineati — quali possono essere i problemi in questo caso e cosa può aiutare a risolvere la terza chiamata alle prestazioni?
Partizionamento — segmentazione o partizionamento
Di solito, il partizionamento viene configurato in modi diversi su ogni database relazionale che ho elencato. Ognuno ha la propria tecnologia, ma sono simili, in generale. La creazione di una nuova partizione porta spesso a determinati problemi.
Di solito, le partizioni vengono configurate in base al «setup» — alla quantità di dati che vengono generati in un giorno. Di norma, il partizionamento viene impostato su un giorno, questo è il minimo. Per le tendenze della nuova partizione — su 1 mese.
I valori possono cambiare in caso di un «setup» molto grande. Se il piccolo «setup» è fino a 5.000 nvps (nuovi valori al secondo), medio — da 5.000 a 25.000, allora grande — sopra 25.000 nvps. Queste sono installazioni grandi e molto grandi, che richiedono un'accurata configurazione proprio del database.
Su installazioni molto grandi, elaborare un segmento in un solo giorno potrebbe non essere ottimale. Ho visto partizioni in MySQL di 40 GB o più al giorno. Si tratta di una quantità di dati molto elevata, che può portare a problemi, e deve essere ridotta.
Quali vantaggi offre il Partitioning?
Partizionamento delle tabelle. Spesso sono file separati sul disco. Il piano delle query seleziona in modo più ottimale una partizione. Di solito, il partizionamento viene effettuato per intervallo — anche per Zabbix è così. Utilizziamo il «timestamp» — il tempo dall'inizio dell'epoca. Qui sono numeri normali. Definisci l'inizio e la fine della giornata — questa è la partizione.
Eliminazione rapida — DELETE. Si seleziona un file/sub-tabella, invece di selezionare righe per la cancellazione.
Accelera notevolmente l'accesso ai dati SELECT — utilizza una o più partizioni, non l'intera tabella. Se richiedi dati risalenti a due giorni fa, questi vengono recuperati dal database più rapidamente, perché è necessario caricare in cache ed emettere solo un file, invece di una grande tabella.
Spesso molte BDs ottimizzano anche INSERT — le inserzioni nella tabella figlia.
TimescaleDB
Per la versione 4.2, ci siamo concentrati su TimescaleDB. È un'estensione per PostgreSQL con un'interfaccia nativa. Questa estensione funziona efficacemente con i dati time series, senza perdere i vantaggi dei database relazionali. TimescaleDB partiziona automaticamente.
In TimescaleDB esiste il concetto di iper-tabella (hypertable), che crei. Al suo interno ci sono chunk — partizioni. I chunk sono frammenti dell'iper-tabella gestiti automaticamente, che non influenzano altri frammenti. Ogni chunk ha il proprio intervallo temporale.

TimescaleDB vs PostgreSQL
TimescaleDB funziona davvero in modo efficiente. I produttori dell'estensione sostengono di utilizzare un algoritmo di elaborazione delle richieste più efficace, in particolare per gli <code>inserts</code>. Man mano che le dimensioni delle dataset di inserimento crescono, l'algoritmo mantiene prestazioni costanti.

Dopo 200 milioni di righe, PostgreSQL di solito inizia a rallentare significativamente, perdendo prestazioni fino a 0. TimescaleDB consente di inserire 'inserts' in modo efficace, indipendentemente dal volume di dati.
Installazione
Installare TimescaleDB è abbastanza semplice per tutti i pacchetti. Nel tutto è descritto in dettaglio — dipende dai pacchetti ufficiali di PostgreSQL. TimescaleDB può anche essere compilato e assemblato manualmente.
Per il DB Zabbix attiviamo semplicemente l'estensione:
echo "CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;" | sudo -u postgres psql zabbix Attivi l'estensione e la crei per il DB Zabbix. L'ultima fase consiste nella creazione della ipertabella.
Migrazione delle tabelle storiche su TimescaleDB
Esiste una funzione specifica per questo create_hypertable:
SELECT create_hypertable('history', 'clock', chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable('history_unit', 'clock', chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable('history_log', 'clock', chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable('history_text', 'clock', chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable('history_str', 'clock', chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable('trends', 'clock', chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable('trends_unit', 'clock', chunk_time_interval => 86400, migrate_data => true);
UPDATE config SET db_extension='timescaledb', hk_history_global=1, hk_trends_global=1 La funzione ha tre parametri. Il primo è la tabella nel DB, per la quale deve essere creata l'ipertabella. Il secondo è campo, in base al quale deve essere creato chunk_time_interval — l'intervallo dei chunk delle partizioni da utilizzare. Nel mio caso l'intervallo è di un giorno — 86.400.
Il terzo parametro è migrare_dati. Se impostato true, tutti i dati attuali vengono trasferiti in chunk pre-creati. L'ho usato di persona migrare_dati. Avevo circa 1 TB, che ha impiegato più di un'ora. Anche in alcuni casi durante i test ho eliminato dati storici di tipo carattere che non erano necessari per il trasferimento.
L'ultimo passo è UPDATE: in db_extension impostiamo timescaledb, affinché il DB comprenda che esiste questa estensione. Zabbix la attiva e utilizza correttamente la sintassi e le query già sul DB — le funzionalità necessarie per TimescaleDB.
Configurazione hardware
Ho utilizzato due server. Il primo è una macchina VMware. È abbastanza piccola: 20 processori Intel® Xeon® CPU E5-2630 v 4 @ 2.20GHz, 16 GB di RAM e un disco SSD da 200 GB.
Ho installato PostgreSQL 10.8 su un sistema operativo Debian 10.8-1.pgdg90+1 e filesystem xfs. Ho eseguito tutte le configurazioni minime necessarie per utilizzare questo database, a parte ciò che userà Zabbix stesso.
Su questa stessa macchina c'era il server Zabbix, PostgreSQL e agenti di carico. Avevo 50 agenti attivi che utilizzavano LoadableModule, per generare molto rapidamente vari risultati: numeri, stringhe. Ho riempito il database con una grande quantità di dati.
Inizialmente la configurazione conteneva 5.000 elementi dati per ogni host. Quasi ogni elemento conteneva un trigger per simulare installazioni reali. In alcuni casi c'erano più di un trigger. Ogni nodo della rete aveva 3.000-7.000 trigger.
Intervallo di aggiornamento degli elementi dei dati — 4-7 secondi. Ho regolato il carico stesso utilizzando non solo 50 agenti, ma aggiungendone altri. Inoltre, ho regolato dinamicamente il carico tramite gli elementi dei dati e ho ridotto l'intervallo di aggiornamento a 4 secondi.
PostgreSQL. 35.000 nvps
Il primo avvio su questo hardware è avvenuto su PostgreSQL pulito — 35.000 valori al secondo. Come si può vedere, l'inserimento dei dati richiede frazioni di secondo — tutto bene e veloce. L'unica cosa è che l'SSD da 200 GB si riempie rapidamente.

Questo è il dashboard delle prestazioni standard di Zabbix — server.

Il primo grafico blu — numero di valori al secondo. Il secondo grafico a destra — carico dei processi di raccolta. Il terzo — carico dei processi interni di raccolta: history syncers e Housekeeper, che qui ha funzionato per un tempo sufficiente.
Il quarto grafico mostra l'uso di HistoryCache. Questo è un buffer prima dell'inserimento nel database. Il quinto grafico verde mostra l'uso di ValueCache, cioè quante hits ha avuto ValueCache per i trigger — si tratta di diverse migliaia di valori al secondo.
PostgreSQL. 50.000 nvps
Poi ho aumentato il carico a 50.000 valori al secondo su questa stessa macchina.

Durante il caricamento con Housekeeper, l'inserimento di 10.000 valori richiedeva 2-3 secondi.

Housekeeper inizia già a interferire con il lavoro.
Dal terzo grafico si vede che, in generale, il carico dei trapper e degli history syncer è ancora al 60%. Nel quarto grafico, HistoryCache inizia già a riempirsi piuttosto attivamente durante il lavoro di Housekeeper. Si è riempito al 20% — circa 0,5 GB.
PostgreSQL. 80.000 nvps
Poi ho aumentato il carico a 80.000 valori al secondo. Si tratta di circa 400.000 elementi di dati e 280.000 trigger.

L'inserimento con un carico di trenta history syncer è già piuttosto alto.
Ho anche aumentato vari parametri: history syncer, cache.

Sul mio hardware, il carico degli history syncer è aumentato al massimo. HistoryCache si è rapidamente riempito di dati — nel buffer si sono accumulati dati da elaborare.
Per tutto questo tempo ho osservato come vengono utilizzati la CPU, la RAM e altri parametri di sistema e ho scoperto che l'utilizzo dei dischi era al massimo.

Ho raggiunto un utilizzo massimo delle capacità del disco su questo hardware e su questa macchina virtuale. Con un'intensità simile, PostgreSQL ha iniziato a scaricare i dati piuttosto attivamente, e il disco non era più in grado di gestire contemporaneamente scrittura e lettura.
Secondo server
Ho preso un altro server, che già aveva 48 processori e 128 GB di RAM. L'ho ottimizzato — ho installato 60 history syncer, e ho raggiunto una velocità accettabile.

In realtà, questo è già il limite delle prestazioni, dove è necessario fare qualcosa.
TimescaleDB. 80.000 nvps
Il mio compito principale è testare le capacità di TimescaleDB sotto il carico di Zabbix. 80 mila valori al secondo — sono molti, con una frequenza di raccolta delle metriche (tranne Yandex, ovviamente) e un "setup" piuttosto grande.

Su ogni grafico c'è un calo — quello è proprio il momento della migrazione dei dati. Dopo i cali nel server Zabbix, il profilo del carico dell'history syncer è cambiato drasticamente — è diminuito di tre volte.
TimescaleDB consente di inserire dati praticamente tre volte più velocemente e di utilizzare meno HistoryCache.
Di conseguenza, i dati verranno forniti in modo tempestivo.
TimescaleDB. 120.000 nvps
In seguito, ho aumentato il numero di elementi dei dati a 500.000. L'obiettivo principale era testare le capacità di TimescaleDB: ho ottenuto un valore stimato di 125.000 valori al secondo.

Questa è una configurazione funzionante che può operare a lungo. Tuttavia, poiché il mio disco aveva solo 1,5 TB, l'ho riempito in pochi giorni.

La cosa più importante è che, nel frattempo, venivano create nuove partizioni in TimescaleDB.
Per le prestazioni, questo è completamente invisibile. Quando le partizioni vengono create in MySQL, ad esempio, è completamente diverso. Di solito, avviene di notte, perché blocca l'inserimento generale, il lavoro con le tabelle e può causare degrado del servizio. In caso di TimescaleDB, questo non avviene.
Per esempio, mostrerò un grafico di molti nella community. Nell'immagine è incluso TimescaleDB, grazie al quale il carico derivante dall'uso di io.weight sulla CPU è diminuito. Anche l'uso degli elementi dei processi interni è diminuito. Si tratta di una normale macchina virtuale su dischi tradizionali, non su SSD.

Conclusioni
TimescaleDB è una buona soluzione per piccole configurazioni., che limitano le prestazioni del disco. Questo permetterà di continuare a lavorare bene fino alla migrazione del DB su hardware più veloce.
TimescaleDB è facile da configurare, offre un incremento delle prestazioni ed è ben integrato con Zabbix e ha vantaggi rispetto a PostgreSQL..
Se stai utilizzando PostgreSQL e non hai intenzione di cambiarlo, ti consiglio di utilizzare PostgreSQL con l'estensione TimescaleDB in combinazione con Zabbix.Questa soluzione funziona efficacemente fino a configurazioni medie.
Quando parliamo di «alte prestazioni» intendiamo . Non è necessario aspettare per conoscere le tecnologie e le pratiche che consentono ai servizi di gestire milioni di utenti. Abbiamo già stilato un elenco di per il 7 e 8 novembre, e ci sono ancora che possono essere proposti.
Iscriviti alla nostra e , in cui sveliamo le caratteristiche della conferenza imminente e scopri come trarre il massimo vantaggio.
Fonte: habr.com
