Una delle principali sfide di Zabbix nel lungo periodo è la crescita del database: un’installazione attiva raccoglie milioni di misurazioni al giorno, e senza una strategia di compressione e pulizia automatica il volume su disco cresce rapidamente.
Compressione dei chunk storici, il processo in due passi
TimescaleDB divide i dati di ogni hypertable in chunk temporali. La compressione agisce sui chunk più vecchi di un intervallo definito, riducendo lo spazio occupato fino al 90% su dati di monitoraggio. Una volta compressi, i chunk non sono più modificabili direttamente (TimescaleDB li decomprime automaticamente in caso di necessità).
Abilitare la compressione su una hypertable TimescaleDB è un processo che avviene in due passi distinti
- Configurare la compressione sulla tabella (ALTER TABLE): definisce come comprimere, quale colonna usare per ordinare i dati all’interno del chunk (compress_orderby) e quale per raggruppare chunk dello stesso item insieme (compress_segmentby). È un’impostazione one-shot sulla tabella
- Aggiungere una policy di compressione (add_compression_policy): schedula quando comprimere. Un job notturno che comprime automaticamente i chunk più vecchi di un intervallo definito
Zabbix esegue entrambi i passi automaticamente all’installazione quando TimescaleDB è abilitato. Non è necessario eseguire questi comandi manualmente su un’installazione standard.
Per conoscenza, queste sono le impostazioni che Zabbix applica sulle tabelle principali
-- Compressione su history (valori float)
ALTER TABLE history SET (
timescaledb.compress,
timescaledb.compress_orderby = 'clock DESC',
timescaledb.compress_segmentby = 'itemid'
);
-- Compressione su history_uint (valori interi, la più voluminosa)
ALTER TABLE history_uint SET (
timescaledb.compress,
timescaledb.compress_orderby = 'clock DESC',
timescaledb.compress_segmentby = 'itemid'
);
-- Compressione su trends
ALTER TABLE trends SET (
timescaledb.compress,
timescaledb.compress_orderby = 'clock DESC',
timescaledb.compress_segmentby = 'itemid'
);
-- Compressione su trends_uint
ALTER TABLE trends_uint SET (
timescaledb.compress,
timescaledb.compress_orderby = 'clock DESC',
timescaledb.compress_segmentby = 'itemid'
);compress_segmentby = ‘itemid’ è la scelta chiave: raggruppa nello stesso chunk tutti i valori dello stesso item, massimizzando il rapporto di compressione su dati di monitoraggio (valori omogenei dello stesso sensore compressi insieme).
Verificare le policy di compressione attive
Connettersi al database di Zabbix
sudo -u postgres psql -d zabbixed eseguire la seguente query
SELECT
job_id,
hypertable_name,
schedule_interval,
config
FROM timescaledb_information.jobs
WHERE proc_name = 'policy_compression'
ORDER BY hypertable_name;che ci darà un output simile al seguente
job_id | hypertable_name | schedule_interval | config
--------+-----------------+-------------------+--------------------------------------------------------------
1008 | auditlog | 1 day | {"hypertable_id": 7, "compress_created_before": "170:00:00"}
1000 | history | 1 day | {"hypertable_id": 1, "compress_after": 612000}
1005 | history_bin | 1 day | {"hypertable_id": 6, "compress_after": 612000}
1004 | history_log | 1 day | {"hypertable_id": 3, "compress_after": 612000}
1002 | history_str | 1 day | {"hypertable_id": 5, "compress_after": 612000}
1003 | history_text | 1 day | {"hypertable_id": 4, "compress_after": 612000}
1001 | history_uint | 1 day | {"hypertable_id": 2, "compress_after": 612000}
1006 | trends | 1 day | {"hypertable_id": 8, "compress_after": 612000}
1007 | trends_uint | 1 day | {"hypertable_id": 9, "compress_after": 612000}
(9 rows)Il campo compress_after nel JSON della colonna config indica l’intervallo in secondi (612000 = 170 ore ≈ 7 giorni). Zabbix imposta questo valore come default per tutte le tabelle history e trends. auditlog usa invece compress_created_before con la stessa soglia espressa come intervallo orario.
Se si vuole aggiungere una policy su una tabella che ne fosse priva, possiamo usare
SELECT add_compression_policy('history', INTERVAL '7 days', if_not_exists => true);
SELECT add_compression_policy('history_uint', INTERVAL '7 days', if_not_exists => true);
SELECT add_compression_policy('trends', INTERVAL '7 days', if_not_exists => true);
SELECT add_compression_policy('trends_uint', INTERVAL '7 days', if_not_exists => true);Attenzione: se la policy esiste già, if_not_exists => true sopprime l’errore ma non modifica l’intervallo e la policy rimane invariata. Per cambiare l’intervallo occorre rimuovere la policy esistente e ricrearla
SELECT remove_compression_policy('history');
SELECT add_compression_policy('history', INTERVAL '30 days');Abbassare l’intervallo aumenta il risparmio di spazio ma riduce la finestra di dati su cui Zabbix può fare query veloci senza decompressione. Un valore tra 7 e 30 giorni è tipicamente un buon compromesso per installazioni di produzione.
Verificare l’efficacia della compressione
Una volta che il job notturno ha compresso i primi chunk, è utile misurare quanto spazio è stato effettivamente risparmiato. La query seguente restituisce per ogni hypertable la dimensione prima e dopo la compressione e il rapporto di riduzione, permettendo di identificare le tabelle che beneficiano di più e quelle su cui la compressione è controproducente.
SELECT
h.hypertable_name,
h.compression_enabled,
pg_size_pretty(cs.before_compression_total_bytes) AS before,
pg_size_pretty(cs.after_compression_total_bytes) AS after,
ROUND(
(1 - cs.after_compression_total_bytes::numeric /
NULLIF(cs.before_compression_total_bytes, 0)) * 100, 1
) AS compression_pct
FROM timescaledb_information.hypertables h
CROSS JOIN LATERAL
hypertable_compression_stats(
format('%I.%I', h.hypertable_schema, h.hypertable_name)::regclass
) cs
ORDER BY h.hypertable_name;Esempio di output su un’installazione attiva da diversi mesi:
hypertable_name | compression_enabled | before | after | compression_pct
-----------------+---------------------+---------+---------+-----------------
auditlog | t | 412 MB | 628 MB | -52.4
history | t | 312 GB | 26 GB | 91.7
history_log | t | 1840 MB | 84 MB | 95.4
history_str | t | 2156 MB | 312 MB | 85.5
history_text | t | 28 GB | 2680 MB | 90.7
history_uint | t | 523 GB | 34 GB | 93.5
trends | t | 22 GB | 2538 MB | 88.7
trends_uint | t | 148 GB | 4240 MB | 97.2
(8 rows)Le tabelle numeriche (history, history_uint, trends_uint) raggiungono i rapporti migliori, tra il 91% e il 97%, perché i valori float e interi dello stesso item si ripetono con pattern molto regolari. history_str e history_text comprimono meno bene (85–91%) per la variabilità del contenuto testuale.
auditlog mostra un valore negativo: la compressione lo rende più grande del 52%. I dati di audit sono JSON eterogenei e non ripetibili, di conseguenza la compressione non trova pattern e aggiunge solo overhead. In presenza di questo risultato è opportuno valutare se disabilitare la compressione su auditlog
SELECT remove_compression_policy('auditlog', if_exists => true);
ALTER TABLE auditlog RESET (timescaledb.compress);Se le colonne before e after mostrano NULL, significa che le tabelle che non hanno ancora chunk compressi. Il job di compressione deve essere eseguito almeno una volta e ci devono essere chunk più vecchi dell’intervallo configurato.
Configurare la retention policy
Per default, Zabbix gestisce la pulizia dei dati storici tramite il proprio housekeeping interno (Administration – General – Housekeeping). Questo meccanismo è attivo fin dall’installazione e non richiede nessuna configurazione aggiuntiva.
TimescaleDB offre un’alternativa nativa: le retention policy eliminano i chunk più vecchi di un intervallo definito direttamente a livello di database, con maggiore efficienza rispetto all’housekeeping di Zabbix. I due meccanismi sono alternativi: usarli entrambi contemporaneamente genera conflitti e overhead inutile.
Se si vuole passare alle retention policy di TimescaleDB, il processo è il seguente:
- Disabilitare l’housekeeping interno di Zabbix per History e Trends: Administration – General – Housekeeping – deselezionare “Enable internal housekeeping” per le sezioni History e Trends
- Configurare le retention policy di TimescaleDB con gli intervalli desiderati con la procedura seguente
Prima di aggiungere le policy, verificare se ne esistono già
SELECT
job_id,
hypertable_name,
schedule_interval,
config
FROM timescaledb_information.jobs
WHERE proc_name = 'policy_retention'
ORDER BY hypertable_name;Se la query restituisce 0 righe, non ci sono retention policy attive e si può procedere. Se ne esistono già, add_retention_policy darebbe errore. In quel caso usare remove_retention_policy(‘nome_tabella”) per rimuoverla e ricrearla con i valori desiderati.
-- Eliminare i dati di history più vecchi di 90 giorni
SELECT add_retention_policy('history', INTERVAL '90 days');
SELECT add_retention_policy('history_uint', INTERVAL '90 days');
SELECT add_retention_policy('history_str', INTERVAL '90 days');
SELECT add_retention_policy('history_log', INTERVAL '90 days');
SELECT add_retention_policy('history_text', INTERVAL '90 days');
-- Eliminare i dati di trend più vecchi di 365 giorni
SELECT add_retention_policy('trends', INTERVAL '365 days');
SELECT add_retention_policy('trends_uint', INTERVAL '365 days');Considerazioni finali
La compressione di TimescaleDB è uno dei principali benefici dell’abbinamento Zabbix + PostgreSQL + TimescaleDB: su installazioni reali riduce il volume delle tabelle di monitoraggio di oltre il 90%, con un impatto diretto sui costi di storage e sulle prestazioni delle query.
Il punto d’azione principale dopo l’installazione è verificare che le policy siano attive e che l’intervallo sia coerente con i requisiti dell’installazione. Per tutto il resto, Zabbix gestisce la configurazione in modo autonomo.