PostgreSQL на 4 ГБ RAM: что ломается под нагрузкой первым
На сервере с 4 ГиБ памяти PostgreSQL может упереться не в размер базы, а в параллельные сортировки, соединения и нехватку памяти для ОС. Разбираем, что проверить в PostgreSQL 16 и какие метрики снять до настройки.

На сервере с 4 ГиБ RAM PostgreSQL может начать писать временные файлы и замедлять запросы задолго до того, как заполнится диск: достаточно увеличить параллельность тяжёлых запросов. Если затем поднять work_mem или число соединений без расчёта, система рискует уйти в нехватку памяти и вызвать OOM. Ниже — разбор для PostgreSQL 16 на Linux; настройки зависят от того, выделены ли серверу все 4 ГиБ и какие запросы он обслуживает.
Четыре гигабайта — не четыре гигабайта для PostgreSQL
Оперативную память делят не только процессы базы. Её используют ядро, системные службы, файловый кэш и, если приложение работает на том же сервере, его процессы. В контейнере ориентируйтесь на лимит cgroup, а не на общий объём памяти виртуальной машины: PostgreSQL может быть ограничен меньшим значением.
Для выделенного сервера PostgreSQL документация предлагает начинать с shared_buffers около 25% памяти. Для 4 ГиБ это примерно 1 ГиБ, но это отправная точка, а не универсальный оптимум. На машине с приложением, мониторингом и другими службами такой объём может оказаться слишком большим. Увеличивать shared_buffers наугад не стоит: PostgreSQL использует и кэш операционной системы, а дополнительная память не гарантирует ускорения.
Главная ловушка — считать, что work_mem выделяется один раз на соединение. Это лимит для отдельной операции запроса, например сортировки или хеширования. В одном запросе таких операций может быть несколько; одновременно исполняются разные запросы, а параллельное выполнение добавляет процессы. Поэтому фактический расход способен заметно превысить значение work_mem, умноженное просто на число соединений.
На 4 ГиБ опаснее не маленький work_mem сам по себе, а его сочетание с числом одновременно работающих тяжёлых запросов.
Термин: spill — перенос части промежуточных данных запроса во временные файлы на диске, когда операции не помещаются в доступную память. Это позволяет продолжить выполнение, но часто увеличивает задержку и нагрузку на диск.
Что обычно проявляется первым
1. Запросы начинают проливать данные на диск
Сортировка, хеш-соединение или агрегирование не помещаются в выделенную память — PostgreSQL использует временные файлы. Пользователь видит рост времени ответа, но не обязательно ошибку. Размер базы здесь не главный показатель: важны форма запроса, объём обрабатываемых строк, индексы и число одновременных выполнений.
Смотрите на временные данные и число временных файлов в статистике базы, а также на запросы в pg_stat_statements, если расширение подключено. Сверяйте эти показатели с нагрузкой и задержками: один большой отчёт может быть допустим, а десятки таких запросов одновременно — уже проблема.
2. Памяти не хватает системе
Попытка вылечить медленные запросы повышением work_mem может дать обратный эффект. Если несколько операций в нескольких запросах запросят память одновременно, серверу может не хватить ресурсов для PostgreSQL и ОС. В худшем случае Linux завершит процесс; в контейнере сработает лимит памяти. Признаки — сообщения OOM в системном журнале, обрывы запросов и скачки задержки.
Не оценивайте риск только по max_connections: не каждое соединение активно, но приложение может внезапно отправить много тяжёлых запросов разом. Пул соединений помогает ограничить параллельность, однако его размер тоже нужно согласовать с числом процессов, которые реально обслуживают запросы.
3. Упирается диск, а не процессор
После проливов и при плохом попадании в кэш запросы чаще читают данные с диска. Время ответа растёт, хотя загрузка CPU может выглядеть умеренной. Проверьте задержки диска, очереди ввода-вывода и объём временных файлов одновременно с метриками базы. Если проблема исчезает после прогрева кэша, это не доказывает, что настройка исправлена: после перезапуска или смены набора запросов эффект может вернуться.
4. Обслуживание таблиц не успевает за записью
При активных изменениях строк autovacuum очищает устаревшие версии данных и поддерживает статистику планировщика. Если обслуживание отстаёт, таблицы и индексы могут разрастаться, а планы запросов — терять точность. Это обычно не первая реакция на увеличение параллельности, но на загруженной системе способно закрепить деградацию. Смотрите, нет ли давно не обработанных таблиц, растущих размеров и устаревшей статистики.
Настройки: что менять и чем рискуете
| Параметр или механизм | Что контролирует | Риск при настройке наугад |
|---|---|---|
| shared_buffers | Кэш страниц, которым управляет PostgreSQL | Слишком большая доля оставит меньше памяти ОС и другим процессам; больший объём не гарантирует меньшего времени ответа |
| work_mem | Память для отдельных операций запроса | Рост умножается на операции, параллельные запросы и процессы; чрезмерно низкое значение увеличивает проливы |
| max_connections | Предел одновременных подключений | Высокий предел не ускоряет запросы и может увеличить конкуренцию за память и CPU |
| Пул соединений | Ограничивает число одновременных запросов к базе | Слишком маленький пул создаёт очередь на стороне приложения; слишком большой не защищает базу от конкуренции |
| maintenance_work_mem и autovacuum_work_mem | Память для обслуживания и работы autovacuum | Увеличение тоже расходует общий бюджет, особенно при параллельном обслуживании нескольких таблиц |
Сначала выясните фактическое поведение, затем меняйте по одному параметру. Для work_mem считайте не только соединения: учитывайте активные запросы, число операций сортировки и хеширования в каждом плане и параллельные процессы. Это оценка верхнего риска, а не точный прогноз — реальное потребление зависит от данных и плана выполнения.
Настройка должна отвечать на измеренный вопрос. Если запросы регулярно проливают большие объёмы, проверьте план, индексы и объём обрабатываемых строк прежде, чем повышать work_mem. Если RAM исчерпывается из-за всплесков одновременной работы, безопаснее сначала ограничить параллельность на уровне приложения или пула, чем без расчёта менять глобальные лимиты.
Как снять замеры без гадания
- Зафиксируйте реальный лимит. Проверьте доступную память ОС или контейнера и выясните, какие ещё процессы живут на сервере. Результат — понятен бюджет именно для базы, а не только общий объём машины.
- Запишите исходную нагрузку. За один и тот же период снимите задержки запросов, CPU, использование памяти, ввод-вывод и число подключений. Укажите параллельность, состав запросов и состояние кэша, чтобы сравнение имело смысл.
- Найдите запросы с дорогими операциями. Используйте статистику запросов и, для конкретного запроса, EXPLAIN (ANALYZE, BUFFERS). ANALYZE выполняет запрос, поэтому на рабочей системе сначала оцените его стоимость и выбирайте безопасное окно.
- Сверьте проливы и нехватку памяти. Сравните временные файлы и байты в статистике базы с системными сообщениями и графиками диска. Проверка успешна, если вы можете связать рост задержки с конкретной нагрузкой, а не только с общим ощущением медленной базы.
- Измените один фактор и повторите тест. Сопоставьте одинаковые интервалы и профиль запросов. Измеряйте не только среднее время, но и хвост задержек, ошибки и память; изменение полезно лишь тогда, когда улучшение не покупается нестабильностью.
Где этот подход ломается
Расчёт по одному типичному запросу не защитит от редкого отчёта, который обрабатывает миллионы строк. Оценка по среднему потреблению RAM не покажет короткий пик. А настройки для выделенного сервера не подойдут машине, где одновременно запущены приложение и фоновые задачи.
На таких системах держите отдельный запас памяти, учитывайте максимальную ожидаемую параллельность и проверяйте поведение при пике, а не только в спокойный час. Если рядом работают аналитические запросы и транзакционная нагрузка, ограничивайте тяжёлые задачи отдельно; иначе один отчёт способен ухудшить задержку обычных операций.
Что делать дальше
Начните не с увеличения памяти в конфигурации, а со сбора базовой линии: лимит RAM, одновременные запросы, временные файлы, задержки диска и системные события OOM. Затем найдите самый дорогой запрос и проверьте его план. Только после этого меняйте work_mem, shared_buffers или пределы соединений — по одному шагу и с повторным замером. Инвалидация кэша и проектирование индексов — отдельные темы; здесь важен порядок диагностики под нагрузкой.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: PostgreSQL 16: Resource Consumption, PostgreSQL 16: Monitoring Database Activity
Частые вопросы
Можно ли просто поставить work_mem побольше, чтобы запросы перестали тормозить?
Если у меня 4 ГБ памяти в контейнере, можно ориентироваться на настройки для сервера с 4 ГБ?
Как понять, что PostgreSQL упёрся именно в RAM?
Что менять первым: shared_buffers, work_mem или число соединений?
Подойдут ли эти рекомендации для PostgreSQL другой версии?
Можно ли проверить тяжёлый запрос через EXPLAIN ANALYZE прямо в проде?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.