Привет, ребята! В этой статье я расскажу о способах оптимизации производительности СУБД PostgreSQL, на базе которой работает Zabbix. Поехали!
Для начала разберемся с процессами Zabbix, которые прямо или косвенно утилизируют БД. В процессе исследования вопроса выяснился один любопытный факт. Оказывается, был такой ZBXNEXT-782, который зарейзил сам Алексей Владышев (напомню, что это автор Zabbix и основатель одноименной компании) аж в 2011 году. В рамках этого реквеста в версии Zabbix 5.4 были наконец-то устранены подключения поллеров к БД. То есть раньше каждый поллер имел собственное подключение к БД для апдейта статуса элементов данных и хостов. Поллеры отвечают за сбор данных. Таким образом, каждый такой поллер, работающий на Zabbix Server занимал одно соединение к БД.
Максимально допустимое число этих поллеров — 1000 штук. Несложно представить к чему это приводило. Выход — использование прокси. В крупных инсталляциях так обычно и поступают.
DBSyncers — процессы Zabbix-сервера, которые используются для записи собранных значений в БД. Их значение по умолчанию 4, но может достигать 100. В Zabbix есть счетчик NVPS (new value per second или новых значений в секунду). Рекомендуется использовать 1 DBSyncer на каждую 1000 NVPS. Если все DBSyncer загружены на 100% или около того, то это обычно вызывает цепную реакцию и влияет на остальные показатели производительности.
Configuration Syncer — это процесс обновления конфигурации Zabbix. По умолчанию запускается каждые 60 секунд, выполняя запросы к БД. Если процесс постоянно занят, в конфигурации необходимо увеличить значение CacheUpdateFrequency (максимум 3600 секунд). Это тоже разгрузит БД.
HousekeepingFrequency — частота удаления устаревших данных. По умолчанию установлено в 1 час, соответственно, максимально период данных, который будет удален, составит 4 часа.
К БД также подключается и веб-бэкэнд. максимальное количество подключений указывается в конфигурации php-fpm (обычно это файл zabbix.conf в /etc/php-fpm.d) в параметре pm.max_children.
В PostgreSQL максимальное количество подключений к БД задается в параметре max_connections. Стоит учитывать все перечисленные выше подключения, а особенно поллеры, если версия вашего Zabbix младше 5.4.
Другие важные параметры конфигурации PostgreSQL:
shared_buffers — буфер данных, который предваряет запись на диск. Обычно задаётся в размере 25% от общего объема ОЗУ на сервере.
effective_cache_size — сколько памяти доступно ОС на сервере. Обычно это 50%.
huge_pages — параметр определяет, будут ли большие страницы запрашиваться из основной области общей памяти. По умолчанию try и его можно таким и оставить. Ядро ОС при этом также должно поддерживать большие страницы.
maintenance_work_mem — задаёт максимальный объём памяти для операций обслуживания БД (vacuum, create index, alter table add foreign key). По умолчанию 64Мб. Можно увеличить.
work_mem — задаёт объём памяти, используемый для внутренних операций сортировки и хеш-таблиц до использования временных файлов на диске. По умолчанию 4Мб.
max_worker_processes — определяет максимальное число фоновых процессов, которое разрешено запускать на сервере.
max_parallel_workers — максимальное число рабочих процессов, которое система сможет поддерживать для параллельных операций. Соотношение max_worker_processes к max_parallel_workers должно равняться числу ядер CPU.
max_parallel_maintenance_workers — максимальное число рабочих процессов, которые могут запускаться одной служебной командой.
max_parallel_workers_per_gather — максимальное число рабочих процессов, которые могут запускаться одним узлом Gather или Gather Merge. Соотношение max_parallel_workers_per_gather к max_parallel_maintenance_workers должно зависеть от количества ядер. Обычно это ½ или ¼.
Перейдем к автоочистке (autovacuum). PostgreSQL использует Multiversion Concurrency Control (MVCC) для обеспечения одновременного доступа к базе данных. Один из побочных эффектов этого метода — операции удаления и обновления, выполняемые в базе данных, оставляют «мертвые» кортежи (строки), отмеченные как удаленные, но фактически не удаляемые с диска. Мертвые кортежи не будут видны транзакциям, но будут занимать дисковое пространство.
В Zabbix есть таблицы, содержащие много данных и получающие множество запросов на удаление / обновление, например, таблицы events, history, history_uint, trends и trends_uint. Эти таблицы особенно раздуваются и для бесперебойной работы БД важна правильная конфигурация автоочистки.
При настройке автоочистки стоит позаботиться о двух вещах:
Как часто очищаются «мертвые» кортежи.
Сколько мертвых кортежей можно очистить за определенный период времени, сведя к минимуму влияние очистки на производительность.
Частота очистки «мертвых» кортежей может быть определена глобально или для каждой таблицы. Лучше определить его глобально, чтобы избежать дополнительного администрирования.
Есть два параметра, которые определяют, когда начинать очистку таблицы: autovacuum_vacuum_threshold и autovacuum_vacuum_scale_factor. Первый определяет минимальное количество кортежей, которые должны быть «мертвыми» для запуска автоочистки, а второй — процент «мертвых» кортежей в таблице до того, как PostgreSQL начнет автоочистку таблицы. Можно использовать autovacuum_vacuum_threshold= 50 и autovacuum_vacuum_scale_factor = 0.01. Это означает, что PostgreSQL начнет очистку таблицы, если количество мертвых кортежей превышает 1% и не менее 50 мертвых кортежей.
Сколько мертвых кортежей можно очистить за определенный период времени, и влияние очистки в системе контролируется функцией троттлинга автоочистки. Очистка — это фоновая задача, которая не должна влиять на запросы пользователей.
Троттлинг автоочистки контролируется параметрами autovacuum_vacuum_cost_delay и autovacuum_vacuum_cost_limit. Первый определяет время, в течение которого процесс автоочистки будет находиться в спящем режиме при превышении предела стоимости, а второй определяет накопленную стоимость, которая приведет к переходу процесса автоочистки в спящий режим при достижении предела.
Стоимость оценивается с использованием значений следующих параметров:
Vacuum_cost_page_hit = 1
Vacuum_cost_page_miss = 10
Vacuum_cost_page_dirty = 20.
Значения autovacuum_vacuum_cost_delay = 20ms и autovacuum_vacuum_cost_limit = 3000 означают, что мы сможем обрабатывать 150 000 (1000/20 * 3000) единиц стоимости в секунду. Это переводится в 1171 МБ/с (150000 x 8/1024) при чтении из shared_buffers, 117 МБ/с (150000 x 8/1024/10) при чтении из с диска и 58 МБ/с (150000 x 8/1024/20) записи страниц, затронутых процессом автоочистки.
Кроме того, нужно определить autovacuum_max_workers = 6 и maintenance_work_mem = 64Мб. Это означает использование 384 Мб памяти для заданий автоочистки. Следующий запрос покажет абсолютное значение и процент «мертвых» кортежей:
SELECT relname, n_live_tup, n_dead_tup, n_dead_tup*100/n_live_tup::float AS dead_percent, last_vacuum, last_autovacuum, autovacuum_count FROM pg_stat_user_tables WHERE n_dead_tup <> 0 AND n_live_tup <>0 ORDER BY relname;
Чтобы упростить задачу генерации корректной конфигурации PostgreSQL можно также использовать утилиту PGTune.
Спасибо за внимание. Надеюсь, вам был полезен этот небольшой обзор настроек производительности и вы сможете что-то улучшить в своей инсталляции Zabbix.