Найти в Дзене
Postgres DBA

Параллельный шторм: как избыточный параллелизм обрушил производительность PostgreSQL

В декабре 2025 года высоконагруженный кластер PostgreSQL неожиданно потерял более половины своей производительности. Виновником оказался не дефицит ресурсов, а каскадный эффект, запущенный неправильно настроенным параллельным выполнением запросов. Это исследование — пошаговая реконструкция того, как микроскопическая ошибка в конфигурации привела к макроскопическому простою, и как подобных катастроф можно избежать в будущем. История служит примером важности полного цикла диагностики: от кода SQL до «железа». Ожидания типа IO Ожидания типа IPC Инцидент развивался в течение часа, начавшись с кажущегося благополучия. Производительность (SPEED) была на пике — около 250 000. Но уже в первые минуты начал расти ключевой индикатор проблем — время ожиданий (WAITINGS). Это стало первым звоночком: система начала тратить больше времени на ожидание, чем на полезную работу. Статистика выявила сильную отрицательную корреляцию (-0.72) между скоростью и ожиданиями: каждое увеличение времени ожиданий н
Оглавление

История каскадного коллапса.
История каскадного коллапса.

Предисловие:

В декабре 2025 года высоконагруженный кластер PostgreSQL неожиданно потерял более половины своей производительности. Виновником оказался не дефицит ресурсов, а каскадный эффект, запущенный неправильно настроенным параллельным выполнением запросов. Это исследование — пошаговая реконструкция того, как микроскопическая ошибка в конфигурации привела к макроскопическому простою, и как подобных катастроф можно избежать в будущем.

История служит примером важности полного цикла диагностики: от кода SQL до «железа».

GitHub - pg-expecto/pg_expecto: Комплекс pg_expecto для статистического анализа производительности и нагрузочного тестирования СУБД PostgreSQL

Исходные материалы

Операционная скорость

График изменения операционной скорости в течении часа до инцидента
График изменения операционной скорости в течении часа до инцидента

Ожидания СУБД

График изменения ожиданий СУБД в течении часа до инцидента
График изменения ожиданий СУБД в течении часа до инцидента

Ожидания типа IO

График изменения ожиданий типа IO в течении часа до инцидента
График изменения ожиданий типа IO в течении часа до инцидента

Ожидания типа IPC

График изменения ожиданий типа IPC в течении часа до инцидента
График изменения ожиданий типа IPC в течении часа до инцидента

Регрессионный и корреляционный анализ

-6

1. Начало конца: тихий рост нагрузки

Инцидент развивался в течение часа, начавшись с кажущегося благополучия. Производительность (SPEED) была на пике — около 250 000. Но уже в первые минуты начал расти ключевой индикатор проблем — время ожиданий (WAITINGS). Это стало первым звоночком: система начала тратить больше времени на ожидание, чем на полезную работу.

Статистика выявила сильную отрицательную корреляцию (-0.72) между скоростью и ожиданиями: каждое увеличение времени ожиданий напрямую било по производительности. К 16:00 скорость упала на 35%, а к 16:25 — на все 52%.

2. Главный виновник: «параллельный шторм»

Глубокий анализ показал, что корень зла — в чрезмерном и неоптимальном параллелизме. Выяснилось, что несколько ресурсоёмких запросов одновременно запустили множество параллельных процессов.

  • Рост IPC-ожиданий (Inter-Process Communication): Их корреляция с общими ожиданиями составила 0.98 — почти идеальная прямая зависимость. Система тратила львиную долю времени на управление параллельными процессами: их завершение (BgWorkerShutdown), сбор результатов (ExecuteGather) и финальную синхронизацию (ParallelFinish). Это были накладные расходы, которые съедали выгоду от параллельного выполнения.
  • Проблемы с вводом-выводом (IO): Параллельные запросы активно читали данные с диска (DataFileRead) и инициализировали общую память (DSMFillZeroWrite). Это создало двойную нагрузку на дисковую подсистему, которая и без того не была оптимизирована для такой работы.

Образовался порочный круг: параллельные запросы → рост IPC и IO → общее замедление → новые запросы встают в очередь → рост ожиданий. Так зародился «параллельный шторм».

3. Фундаментальные причины на уровне инфраструктуры

Симптомы на уровне СУБД были лишь верхушкой айсберга. Расследование опустилось ниже — на уровень операционной системы и «железа», где обнаружились системные проблемы:

  1. Дисковый парадокс: Основной диск для данных (vdb) демонстрировал аномально высокую задержку записи (часто выше 5 мс) при низкой общей утилизации (2-6%). Это классический признак проблемы с качеством обслуживания, характерный для HDD, обрабатывающих мелкие случайные запросы. Скорее всего, он просто не соответствовал требованиям рабочей нагрузки.
  2. Агрессивное и неэффективное кэширование: Операционная система использовала под кэш более 90% оперативной памяти (59 из 64 ГБ), оставляя мизерный запас для буферов записи. При этом кэш не снижал нагрузку на диск, а лишь коррелировал с ней — признак неверной политики управления памятью.
  3. Шквал прерываний: Несмотря на низкую общую загрузку CPU, система обрабатывала до 17 000 прерываний в секунду, что создавало скрытый contention (конфликт за ресурсы) и инвалидировало кэш процессора, дополнительно замедляя вычисления СУБД.

Итоговая цепочка: Агрессивное кэширование → нехватка буферов для записи → высокие задержки медленного HDD → блокировка транзакций в СУБД → лавина прерываний и переключений контекста → полномасштабный коллапс производительности.

4. Уроки и рекомендации

Расследование позволило сформулировать чёткий план по предотвращению повторения инцидента.

Немедленные действия:

  • Для СУБД: Жёстко ограничить максимальное количество параллельных воркеров (max_parallel_workers_per_gather), временно отключить параллелизм для самых «тяжёлых» запросов, добавить нехватающие индексы.
  • Для ОС: Перенастроить политику кэширования памяти (уменьшить vm.dirty_ratio), перевести проблемный диск на более подходящий планировщик ввода-вывода (deadline).

Стратегические изменения:

  • Апгрейд инфраструктуры: Разместить WAL (журнал транзакций) на самом быстром диске (желательно SSD/NVMe). Рассмотреть переход на SSD и для основных данных.
  • Изоляция ресурсов: Настроить привязку процессов PostgreSQL и обработчиков прерываний к разным ядрам CPU для уменьшения contention.
  • Архитектурный рефакторинг: Выделить отдельные реплики для аналитических запросов, внедрить кэширование результатов на уровне приложения.

Заключение

Этот инцидент — наглядный учебник по комплексному подходу к диагностике. Проблема не была локализована в одном месте: она эшелонированно расположилась в настройках СУБД, политике ОС и ограничениях аппаратного обеспечения. Современные высоконагруженные системы — это сложные организмы, где сбой в одном узле запускает каскад по всем остальным. Ключ к устойчивости — не только мониторинг «верхнеуровневых» метрик вроде загрузки CPU, но и глубокое понимание взаимодействия всех компонентов стека: от SQL-запроса до latency диска. Только так можно предсказать и остановить следующий «параллельный шторм».