Спустя 2 года решил обновить запись Zabbix: Чистка базы данных, так как есть более эффективные методы борьбы с «распуханием» базы , да и в целом информации накопилось больше чем можно удержать в голове и evernote.
Основная задача, которую пытаемся решить — малой кровью обеспечить хорошую производительность сервера и предотвратить неконтролируемый рост базы.
Характеристики текущего сервера:
Ubuntu 14.04.4
psql (PostgreSQL) 9.3.13
Zabbix 3.4.4
Cpu: 8 x Intel(R) Xeon(R) CPU E5-2660 v4 @ 2.00GHz
MemTotal: 16Gb
Disk: 300Gb Raid 10 4x15k
Состояние Zabbix:
Количество узлов сети (активированных/деактивированных/шаблонов) >1k
Количество элементов данных (активированных/деактивированных/неподдерживаемых) >60k
Количество триггеров (активированных/деактивированных [проблема/ок]) >20k
Требуемое быстродействие сервера, новые значения в секунду 748
Расчет планируемого места в базе:
В зависимости от необходимого срока хранения и элементов данных.
У нас 60к элементов данных, опрашиваем мы их каждую минуту, т.е. в день у нас получается:
60000 событий x 60 минут x 24 часа = 86400000 событий в день.
Одно событие в среднем занимает около 90 байт, т.е.
86400000 x 90 байт = 7,77Гб в день.
Для трендов Zabbix хранит только ежечасную статистику для каждого элемента (max/min/avg/count), выкидываем из формулы «минуты»:
60000 событий x 24 часа x 90 байт = 0,13Гб в день.
Итог: месяц хранения истории обойдется нам в 230Гб и 4Гб в виде трендов.
Если сделать запрос в базу, то в столбце «size» можно увидеть «большие» таблицы и их размер, который в целом соответствует расчетам.
SELECT RESULT.table_name, RESULT.freespace AS fororder, pg_size_pretty(RESULT.size) AS SIZE, pg_size_pretty(RESULT.freespace) AS freespace, RESULT.freespace * 100 / RESULT.size AS percent_free FROM (SELECT t.table_name, pg_total_relation_size(t.table_name) AS SIZE, SUM(s.avail) AS freespace FROM (SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = 'public') AS t, LATERAL pg_freespace(t.table_name) AS s GROUP BY t.table_name) AS RESULT ORDER BY fororder DESC LIMIT 20; TABLE_NAME | fororder | SIZE | freespace | percent_free ---------------------+-------------+---------+------------+-------------- history | 12331130656 | 59 GB | 11 GB | 19 history_uint | 146627744 | 212 GB | 140 MB | 0 auditlog | 11642944 | 2891 MB | 11 MB | 0 trends_uint | 10216192 | 9845 MB | 9977 kB | 0 trends | 3569984 | 3208 MB | 3486 kB | 0 sessions | 3255808 | 3603 MB | 3180 kB | 0 alerts | 1384288 | 134 MB | 1352 kB | 0 item_discovery | 1074912 | 408 MB | 1050 kB | 0 history_str | 585952 | 651 MB | 572 kB | 0 triggers | 566656 | 67 MB | 553 kB | 0 items | 379808 | 55 MB | 371 kB | 0 history_text | 196992 | 232 MB | 192 kB | 0 history_log | 152128 | 38 MB | 149 kB | 0 hosts | 133312 | 13 MB | 130 kB | 0 problem | 58272 | 41 MB | 57 kB | 0 profiles | 26080 | 5560 kB | 25 kB | 0 users | 20064 | 96 kB | 20 kB | 20 images | 8736 | 1200 kB | 8736 bytes | 0 interface_discovery | 8448 | 96 kB | 8448 bytes | 8 dbversion | 8128 | 40 kB | 8128 bytes | 19 (20 ROWS) |
Лечение:
1) Запросы для чистки базы:
https://github.com/burner1024/zabbix-sql/blob/master/delete-old-data.pg.sql
-- keep 1 week of history and 3 months of trends \SET history_interval 7 \SET trends_interval 90 DELETE FROM alerts WHERE age(to_timestamp(alerts.clock)) > (:history_interval * INTERVAL '1 day'); DELETE FROM acknowledges WHERE age(to_timestamp(acknowledges.clock)) > (:history_interval * INTERVAL '1 day'); DELETE FROM events WHERE age(to_timestamp(events.clock)) > (:history_interval * INTERVAL '1 day'); DELETE FROM history WHERE age(to_timestamp(history.clock)) > (:history_interval * INTERVAL '1 day'); DELETE FROM history_uint WHERE age(to_timestamp(history_uint.clock)) > (:history_interval * INTERVAL '1 day') ; DELETE FROM history_str WHERE age(to_timestamp(history_str.clock)) > (:history_interval * INTERVAL '1 day') ; DELETE FROM history_text WHERE age(to_timestamp(history_text.clock)) > (:history_interval * INTERVAL '1 day') ; DELETE FROM history_log WHERE age(to_timestamp(history_log.clock)) > (:history_interval * INTERVAL '1 day') ; DELETE FROM trends WHERE age(to_timestamp(trends.clock)) > (:trends_interval * INTERVAL '1 day'); DELETE FROM trends_uint WHERE age(to_timestamp(trends_uint.clock)) > (:trends_interval * INTERVAL '1 day') ; |
Непосредственно запуск:
time sudo -u postgres psql -A -R ' : ' -P 'footer=off' zabbix < delete-old-data.pg.sql |
2) Обработка базы при помощи pgtoolkit:
pgtoolkit — инструмент для уменьшения раздувания таблиц и индексов без тяжелых блокировок и полной перестройки таблицы (https://github.com/grayhemp/pgtoolkit)
Непосредственно запуск:
time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -y 10 --reindex #Или по очереди: time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -t alerts -y 10 --reindex time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -t acknowledges -y 10 --reindex time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -t events -y 10 --reindex time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -t history -y 10 --reindex time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -t history_uint -y 10 --reindex time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -t history_str -y 10 --reindex time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -t history_text -y 10 --reindex time sudo -u postgres /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -t history_log -y 10 --reindex
Иногда может возникнуть необходимость проверить и удалить временные индексы, оставшиеся от работы pgcompact:
SELECT * FROM pg_indexes WHERE indexname LIKE '%pgcompact%'; schemaname | tablename | indexname | tablespace | indexdef ------------+-----------------+-----------------------+------------+----------------------------------------------------------------------------------------------- public | hostmacro | pgcompact_index_12057 | | CREATE UNIQUE INDEX pgcompact_index_12057 ON hostmacro USING btree (hostid, macro) public | graph_discovery | pgcompact_index_29490 | | CREATE UNIQUE INDEX pgcompact_index_29490 ON graph_discovery USING btree (graphid) public | hosts_templates | pgcompact_index_4305 | | CREATE UNIQUE INDEX pgcompact_index_4305 ON hosts_templates USING btree (hostid, templateid) public | hosts_templates | pgcompact_index_21016 | | CREATE UNIQUE INDEX pgcompact_index_21016 ON hosts_templates USING btree (hostid, templateid) DROP INDEX pgcompact_index_12057; DROP INDEX pgcompact_index_29490; DROP INDEX pgcompact_index_4305; DROP INDEX pgcompact_index_21016; |
Результат работы можно увидеть на графиках.
В данном случае я пропустил момент распухания базы и на раздел пришлось экстренно добавлять место.
Чтобы не пропускать переполнение диска, рекомендуется добавить задание в cron:
sudo -u postgres /usr/bin/flock -w 0 /var/run/postgresql/backup_zabbix_psql.lock /usr/bin/psql -A -R ' : ' -P 'footer=off' zabbix < /opt/delete-old-data.pg.sql sudo -u postgres /usr/bin/flock -w 0 /var/run/postgresql/backup_zabbix_pgcompact.lock /opt/pgtoolkit/bin/pgcompact -v info -d zabbix -y 10 --reindex
Если у вас mysql:
При использовании движка базы данных InnoDB, все таблицы и индексы хранятся в системном табличном пространстве (в одном файле /var/lib/mysql/ibdata).
Для того, чтобы хранить каждую таблицу InnoDB и связанные индексы в отдельных файлах — нужно активировать опцию innodb_file_per_table.
Алгоритм включения опции следующий:
- останавливаем приложения, использующие базу данных;
- делаем резервную копию базы данных;
- удаляем базу данных;
- останавливаем MySQL-сервер;
- в конфигурационном файле /etc/mysql/my.cnf удаляем параметр innodb_data_file_path и добавляем параметр innodb_file_per_table;
- удаляем файлы /var/lib/mysql/ibdata, /var/lib/mysql/ib_logfile0, /var/lib/mysql/ib_logfile1 и т. д.;
- запускаем MySQL-сервер;
- создаем базу данных;
- восстанавливаем данные из резервной копии;
- проверяем наличие файлов с расширением *.ibd для каждой таблицы;
- запускаем остановленные в первом пункте сервисы.