Периоды наблюдения:
Конфигурация стенда:
Ключевые изменения в P2 (по сравнению с P1):
Предоставленный отчёт содержит обработанные статистические данные и выводы, но для углублённой диагностики и подтверждения выдвинутых гипотез необходимы следующие данные (🟡/🔴 — в зависимости от вероятной ценности):
Периоды наблюдения:
Конфигурация стенда:
Ключевые изменения в P2 (по сравнению с P1):
Предоставленный отчёт содержит обработанные статистические данные и выводы, но для углублённой диагностики и подтверждения выдвинутых гипотез необходимы следующие данные (🟡/🔴 — в зависимости от вероятной ценности):
...Читать далее
Оглавление
Общая информация
Периоды наблюдения:
- Период 1 (P1): 2026-03-11 14:35 – 15:35 (базовый уровень)
- Период 2 (P2): 2026-03-11 15:35 – 16:35 (инцидент производительности)
Конфигурация стенда:
- PostgreSQL 15.13 на Linux x86_64.
- Аппаратно: 192 логических ядра (Intel Xeon Platinum 8280L, 4 сокета), 1007 ГБ ОЗУ, NUMA 4 узла.
- Ключевые настройки СУБД:
- shared_buffers = 246 ГБ (🟢 соответствует ~24% ОЗУ)
- effective_cache_size = 730 ГБ (🟢 адекватно объёму кэша ОС)
- work_mem = 1 ГБ на операцию сортировки/хеша
- maintenance_work_mem = 16 ГБ, autovacuum_work_mem = 2 ГБ
- checkpoint_timeout = 15 мин, max_wal_size = 8 ГБ
- max_parallel_workers_per_gather = 0 (🟡 параллелизм запросов отключён)
- synchronous_commit = remote_write
- Дисковая подсистема:
- vdg – выделенное устройство под WAL
- vdh, vdi, vdj, vdk – LVM-пул для данных (/data)
- vde – /log, vdc – /backup (не анализировались)
Ключевые изменения в P2 (по сравнению с P1):
- 🟢 Операционная скорость (SPEED) перешла от слабого роста к устойчивому падению (R²=0.94, наклон -44.09).
- 🟢 Ожидания СУБД (WAITINGS) стали уверенно расти (R²=0.58, наклон +37.28).
- 🟢 Обратная корреляция между скоростью и ожиданиями усилилась с умеренной (r=-0.55) до сильной (r=-0.77).
- 🟢 Утилизация устройств данных (vdh–vdk) превысила 90%, очередь запросов (aqu_sz) выросла с ~2.0 до ~2.5.
- 🟢 Объём записи на WAL-устройство (vdg) вырос вдвое (с 7.8 до 16.0 МБ/с медианно).
- 🟢 Появились новые типы ожиданий: WALSync (IO) и блокировки tuple (Lock).
Ключевые проблемы СУБД и инфраструктуры
1. Дисковая подсистема данных достигла насыщения
- 🟢 Утилизация устройств vdh–vdk в P2 стабильно >90% (ALARM по условиям отчёта). Медианный рост w/s на 118% и wMB/s на ≈100% привёл к выходу на плато производительности.
- 🟢 Операционная скорость (SPEED) стала сильно коррелировать с объёмом записи на диски данных (r=0.73, R²=0.54). В P1 такая связь была слабой (r≈0.46). Это прямое свидетельство того, что пропускная способность дисковой подсистемы стала узким местом.
- 🟡 Рост очереди запросов (aqu_sz с 2.0 до 2.5) при сохранении низких задержек (r_await, w_await <0.3 мс) указывает на высокую параллельную нагрузку, с которой устройства справляются, но их пропускная способность уже исчерпана.
2. Резкое увеличение нагрузки на WAL и появление ожиданий WALSync
- 🟢 Запись на vdg выросла в 2 раза по объёму (медиана wMB/s: 7.75 → 16.0) и на 85% по операциям (w/s: 373 → 689).
- 🟢 В P2 появились ожидания WALSync, составляющие 11% от всех ожиданий IO. Они отсутствовали в P1.
- 🟡 Утилизация vdg осталась низкой (медиана 10%), что говорит о достаточной производительности устройства, но возросший объём записи увеличивает латентность синхронизации WAL, особенно при synchronous_commit = remote_write.
3. Критическая конкуренция за легковесные блокировки (LWLock)
- 🟢 В P1 99% вариации общих ожиданий объяснялось LWLock (R²=0.99). В P2 объясняющая сила снизилась до 55%, но LWLock сохранил критический уровень взвешенной корреляции (ВКО=0.30).
- 🟢 Основные события внутри LWLock:
- BufferMapping (~30%) – конкуренция за доступ к буферному кэшу. Вероятная причина: высокая частота обращений к одним и тем же страницам данных или недостаточное количество буферных разделов (lwlock_shared_limit не задан).
- WALWrite (~26%) – конкуренция при записи WAL, коррелирует с возросшей нагрузкой на vdg.
- pgpro_stats (~18%) – ожидания внутри расширения сбора статистики.
4. Аномальная активность расширений (Extension) в P2
- 🟢 По интегральному приоритету тип ожиданий Extension вышел на первое место в P2 (0.6625 против 0.37 у LWLock). В P1 значимой корреляции с общими ожиданиями не было.
- 🟢 Ожидания Extension стали очень сильно коррелировать с user time CPU (r=0.91, R²=0.82) и с прерываниями (r=0.83, R²=0.68). Это указывает на интенсивное выполнение кода расширений в user space, вероятно, с большим количеством системных вызовов.
- 🟢 Проблемный запрос -5038981907002478858 генерирует 33.7% всех ожиданий Extension (в P1 было 8.5%) и 32.2% всех ожиданий LWLock (было 6.1%). Его доля в общей нагрузке резко возросла.
5. Рост конкуренции за строки (блокировки tuple)
- 🟢 В P2 появились блокировки tuple, отсутствовавшие в P1, которые составили 20.4% от всех ожиданий Lock. Основной тип Lock по-прежнему transactionid (79%).
- 🟡 Это свидетельствует о возросшей конкуренции на уровне строк в транзакциях (UPDATE/DELETE или INSERT с конфликтами уникальности). Топ-запросы демонстрируют ненулевую долю tuple-ожиданий.
6. Признаки роста общей загрузки CPU при неполной диагностике
- 🟢 В P2 тренд cpu idle перешёл к устойчивому падению (R²=0.79, наклон -41.71). Медианный idle снизился с 69% до 72%? (в отчёте противоречие: медиана idle выросла на 3 п.п., но тренд отрицательный). 🟡 Требуется проверка исходных рядов для точной интерпретации.
- 🟡 Рост iowait с 2% до 3% лишь частично объясняет снижение idle. Недостаточно данных для разбивки us/sy/wa во времени. Возможно увеличение steal (гипервизор) или рост нагрузки на user/system, не отражённое в граничных значениях.
7. Память: свободной ОЗУ <5%, но без подкачки
- 🟢 В обоих периодах 100% времени free RAM < 5% (≈13 ГБ). Swap не используется.
- 🟡 Это типично для heavily loaded PostgreSQL при активном файловом кэше (≈720 ГБ). Риск заключается в возможном вытеснении страниц shared_buffers или кэша ОС при пиковых аллокациях памяти процессами (например, при большом количестве сессий с высоким work_mem). Данных о количестве сессий нет.
Рекомендации по оптимизации СУБД и инфраструктуры
⚠️ Все рекомендации даны на основе предоставленного отчёта и носят статус 🟡 (вероятно полезны) или 🔴 (требуют дополнительной диагностики и тестирования в конкретной среде). Окончательные решения должны приниматься после проверки гипотез.
СУБД
1. Исследовать и оптимизировать запрос -5038981907002478858 (🔴 приоритет)
- Почему: Запрос стал основным генератором ожиданий Extension и LWLock в P2.
- Действия:
- Получить план выполнения (EXPLAIN (ANALYZE, BUFFERS, TIMING)).
- Проверить, какие расширения вызываются в запросе. Оценить их необходимость и накладные расходы.
- Рассмотреть возможность рефакторинга запроса, добавления индексов или изменения логики для снижения частоты вызовов расширений.
- Ожидаемый эффект: Снижение нагрузки на Extension и, как следствие, уменьшение конкуренции за CPU и LWLock.
2. Проанализировать и, возможно, снизить конкуренцию за LWLock BufferMapping (🟡)
- Почему: LWLock BufferMapping доминирует среди легковесных блокировок (30%).
- Действия:
- Проверить статистику pg_stat_bgwriter на предмет buffers_alloc и buffers_backend_fsync.
- Оценить равномерность доступа к страницам. Высокая конкуренция может быть следствием «горячих» блоков данных.
- Рассмотреть увеличение shared_buffers (текущие 246 ГБ при кэше ОС 720 ГБ) — потенциально может снизить частоту обращений к кэшу ОС, но требует тестирования.
- Изучить возможность увеличения числа буферных разделов через параметр lwlock_shared_limit (только после анализа текущего распределения блокировок).
- Ожидаемый эффект: Снижение LWLock ожиданий, улучшение пропускной способности при работе с буферным кэшем.
3. Оптимизировать работу с WAL для уменьшения ожиданий WALSync (🟡)
- Почему: Удвоение записи WAL и появление ожиданий синхронизации.
- Действия:
- Проанализировать причины роста записи WAL: возможно, увеличилось число транзакций или объём изменяемых данных. Использовать pg_stat_statements для поиска запросов с высоким wal_bytes.
- Проверить настройки wal_writer_delay (по умолчанию 200 мс) и wal_writer_flush_after (по умолчанию 1 МБ). Адаптация под возросшую нагрузку может сгладить пики.
- Рассмотреть группировку мелких транзакций на стороне приложения.
- Ожидаемый эффект: Снижение латентности синхронизации WAL, уменьшение влияния на WALSync.
4. Рассмотреть включение параллелизма запросов (🟡)
- Почему: max_parallel_workers_per_gather = 0 полностью отключает параллельное выполнение. При наличии 192 ядер и сканировании больших таблиц это может приводить к неэффективному использованию CPU.
- Действия:
- Включить параллелизм с осторожностью: установить max_parallel_workers_per_gather = 2 или 4, max_parallel_workers и max_worker_processes адекватно.
- Отслеживать влияние на cpu us/sy и iowait.
- Ожидаемый эффект: Потенциальное ускорение аналитических запросов, снижение времени выполнения, но может увеличить нагрузку на CPU и I/O.
5. Проверить накладные расходы расширения pgpro_stats (🟡)
- Почему: Ожидания pgpro_stats составляют 18% от всех LWLock. Возможно, сбор детальной статистики создаёт избыточную нагрузку.
- Действия:
- Оценить частоту сбора и уровень детализации. При необходимости снизить.
- Временно отключить для проверки влияния на LWLock и CPU (в тестовой среде).
- Ожидаемый эффект: Снижение LWLock, освобождение ресурсов CPU.
6. Проанализировать причину появления блокировок tuple (🟡)
- Почему: Новый тип блокировок в P2 указывает на конкуренцию за строки.
- Действия:
- Использовать представление pg_stat_user_tables для поиска таблиц с высоким числом n_tup_upd, n_tup_del.
- Проверить наличие необходимых индексов на столбцах, участвующих в условиях WHERE для UPDATE/DELETE. Отсутствие индекса может приводить к блокировке большего числа строк, чем необходимо.
- Анализировать логи на предмет deadlock'ов или длительных транзакций.
- Ожидаемый эффект: Снижение конкуренции за строки, уменьшение Lock-ожиданий.
Инфраструктура
7. Расширение пропускной способности дисковой подсистемы данных (🔴 приоритет)
- Почему: Устройства данных достигли утилизации >90% и стали узким местом.
- Действия:
- Профилировать ввод-вывод на уровне ОС (iostat -x 1, pidstat -d) для подтверждения, что именно запросы PostgreSQL создают нагрузку.
- Оценить возможность добавления более производительных дисков (NVMe) или увеличения числа устройств в LVM-пуле.
- Проверить, оптимально ли настроен effective_io_concurrency = 300. При высоких очередях на NVMe может потребоваться корректировка.
- Ожидаемый эффект: Устранение узкого места, возможность обслуживать возросшую нагрузку записи без деградации скорости.
8. Мониторинг WAL-устройства и возможное ускорение (🟡)
- Почему: Нагрузка на vdg выросла вдвое, появились ожидания WALSync.
- Действия:
- Убедиться, что vdg не используется другими процессами.
- Мониторить w_await на vdg; если задержки растут, рассмотреть более быстрое устройство или отдельный том с высокими IOPS.
- Ожидаемый эффект: Снижение влияния записи WAL на общую производительность.
9. Контроль использования памяти (🟡)
- Почему: Свободной ОЗУ <5%, хотя подкачки нет. Риск вытеснения страниц при пиковых нагрузках.
- Действия:
- Настроить мониторинг memory_free и memory_cache с алертами при резком падении кэша.
- Оценить количество одновременных сессий. Если оно велико, возможно избыточное потребление памяти из-за work_mem = 1 ГБ. Рассмотреть снижение work_mem для массовых сессий или установку лимитов на уровне пула соединений.
- Ожидаемый эффект: Предотвращение вытеснения страниц shared_buffers, сохранение стабильности кэша.
10. Детальное профилирование CPU (🟡)
- Почему: Устойчивое снижение cpu idle не полностью объясняется ростом iowait.
- Действия:
- Использовать mpstat -P ALL для анализа загрузки по ядрам.
- Проверить steal в виртуализированной среде (KVM). Рост steal может имитировать увеличение iowait или system.
- Применить perf top для выявления hot-функций в ядре или PostgreSQL.
- Ожидаемый эффект: Выявление скрытых причин роста загрузки CPU.
Необходимая дополнительная информация для продолжения анализа
Предоставленный отчёт содержит обработанные статистические данные и выводы, но для углублённой диагностики и подтверждения выдвинутых гипотез необходимы следующие данные (🟡/🔴 — в зависимости от вероятной ценности):
Критически важные (без них анализ неполон):
- 🔴 Тексты и планы выполнения топ-запросов (особенно -5038981907002478858 и -4280293605113329019) с EXPLAIN (ANALYZE, BUFFERS, TIMING, VERBOSE).
- 🔴 Логи PostgreSQL за периоды P1 и P2, содержащие сообщения об ошибках, deadlock'ах, checkpoint'ах, autovacuum.
- 🔴 Детальная статистика по таблицам и индексам из pg_stat_user_tables, pg_stat_user_indexes за указанные периоды.
- 🔴 Данные о количестве активных сессий и их состояниях (pg_stat_activity) во времени.
Важные для уточнения гипотез:
- 🟡 Исходные временные ряды метрик (вместо агрегированных граничных значений и медиан) для:
- CPU us, sy, wa, id, st (mpstat)
- vmstat (procs, memory, swap, io, system, cpu) с минутным разрешением
- iostat -x по всем устройствам с минутным разрешением
- 🟡 Статистика pg_stat_bgwriter для анализа эффективности буферного кэша и контрольных точек.
- 🟡 Информация о расширениях (какие установлены, их версии, конфигурация pgpro_stats).
- 🟡 Данные о настройках ОС (планировщик ввода-вывода, параметры ядра vm.dirty_*, vm.vfs_cache_pressure).
- 🟡 Профиль нагрузки на диск с помощью pidstat -d или iotop для идентификации процессов-генераторов I/O.
Желательные для полной картины:
- 🟡 Результаты трассировки проблемного запроса с auto_explain.log_analyze = on и auto_explain.log_min_duration = 0 (на короткий промежуток).
- 🟡 Дамп pg_locks в моменты пиковых ожиданий Lock/LWLock.
- 🟡 Метрики NUMA (numastat) для выявления возможного дисбаланса доступа к памяти.
Ограничение анализа:
Без перечисленных данных любые рекомендации по изменению параметров конфигурации PostgreSQL (shared_buffers, work_mem, lwlock_shared_limit и др.) являются спекулятивными (🔴) и должны проверяться в тестовой среде. Текущий анализ основан исключительно на агрегированных отчётах, которые не позволяют однозначно установить причинно-следственные связи на уровне отдельных запросов и системных вызовов.