4 ГБ памяти под нагрузкой: что сломается первым
На машине с 4 ГБ памяти приложение редко падает из-за одной большой операции. Обычно раньше заканчивается запас для ОС, базы, воркеров или файлового кеша. Разбираем бюджет памяти и порядок отказов под нагрузкой.

На сервере с 4 ГБ RAM под нагрузкой первым часто ломается не само приложение, а запас памяти вокруг него: база начинает вытеснять кеш, воркеры копят запросы, ядро запускает OOM-killer, а соседние процессы получают задержки или 502. Ниже — разбор для Linux-сервера с cgroup v2 и PostgreSQL 16; это не бенчмарк, а модель, по которой можно найти реальный предел своей системы.
Почему «4 ГБ на приложение» — неправильный бюджет
Номинальный объём памяти виртуальной машины не равен памяти, доступной процессу. Часть забирают ядро, systemd, сетевой стек, файловый кеш, агент мониторинга, логирование и сам рантайм. Если на той же машине работает PostgreSQL, ему нужен отдельный запас под соединения, сортировки, временные файлы и фоновые процессы.
Вместо одного числа считайте четыре слоя:
- Базовый слой ОС. Ядро, системные службы, SSH, журналирование и мониторинг.
- Фиксированный слой сервисов. Nginx, приложение, PostgreSQL, очереди и агенты.
- Переменный слой. Память, которая растёт вместе с числом воркеров, соединений, запросов и размером ответа.
- Аварийный запас. Свободная память для пиков, перезапуска процесса и кратковременного всплеска нагрузки.
Если сумма первых трёх слоёв регулярно подходит к объёму машины, система уже работает на пределе. «Свободно 300 МБ» не означает, что можно безопасно принять ещё сотню запросов: часть страниц памяти может быть быстро освобождена, а часть — нет.
На машине с 4 ГБ главный вопрос не «сколько памяти потребляет приложение», а «какой процесс получит память последним, когда все остальные уже заняли свою долю».
Как распределяется память на практике
Возьмём условную машину с 4 ГБ RAM. Числа ниже не являются универсальными лимитами и не заменяют измерения. Они показывают, почему арифметика «приложение занимает 2 ГБ, значит остаётся ещё 2 ГБ» опасна.
| Потребитель | Что растёт под нагрузкой | Что измерять |
|---|---|---|
| ОС и службы | Фоновые процессы, журналирование, файловый кеш | RSS процессов, page cache, давление на память |
| Прокси или веб-сервер | Соединения, буферы, TLS и очереди | Активные соединения, длину очереди, ошибки 502/504 |
| Приложение | Число воркеров, heap, очереди задач, большие ответы | RSS каждого воркера, паузы сборщика, время ответа |
| PostgreSQL | Соединения, рабочая память операций, фоновые процессы | Число сессий, активные запросы, временные файлы, кеш |
| Резерв | Всплеск параллельности и перезапуск | Минимум доступной памяти и события OOM |
RSS — объём физических страниц памяти, связанных с процессом. Он полезен для наблюдения, но его нельзя бездумно складывать: общие библиотеки могут учитываться у нескольких процессов. Для ограничения контейнеров важнее смотреть на память cgroup целиком, а не только на RSS одного PID.
Что ломается первым
1. Запас памяти и файловый кеш
Пока памяти достаточно, Linux использует свободное место для кеширования файлов. Это ускоряет чтение, но создаёт ложное ощущение, что сервер «занят почти полностью». Сам по себе кеш не равен утечке: ядро может освободить его при необходимости.
Проблема начинается, когда освобождение кеша уже не спасает. Тогда система активнее вытесняет страницы процессов, растут задержки памяти и I/O. Приложение может оставаться живым, но время ответа увеличивается, а таймауты появляются до явного падения.
2. Воркеры приложения
У процесса есть базовый расход памяти и переменная часть на запрос. При запуске нескольких воркеров базовая часть повторяется. Если один воркер занимает 250 МБ, пять воркеров — это не «250 МБ приложения», а как минимум несколько таких адресных пространств плюс общие страницы и память запросов.
Первым симптомом становится не обязательно OOM. Очередь запросов растёт, прокси закрывает соединения по таймауту, а новые воркеры не могут корректно стартовать. Особенно быстро это проявляется при генерации больших JSON-ответов, обработке изображений, экспорте данных и загрузке файлов.
3. Соединения с базой
Лимит соединений — не бесплатная настройка. Каждая сессия создаёт состояние, а параллельные запросы могут потреблять рабочую память сверх базового расхода процесса. Если приложение открывает отдельное соединение для каждого воркера и фоновой задачи, пиковая параллельность незаметно превращается в пиковое потребление памяти PostgreSQL.
Слишком низкий лимит приводит к ожиданию соединения. Слишком высокий — к конкуренции за память. Пул соединений уменьшает количество одновременно открытых сессий, но не исправляет запрос, который сам создаёт огромную сортировку или соединение таблиц.
4. Временные операции базы
Запрос может быть дешёвым в обычном режиме и дорогим на редком наборе параметров. Сортировка, агрегация или соединение таблиц используют рабочую память; если её не хватает, PostgreSQL может перейти к временным файлам. Это не обязательно приводит к немедленному падению, но увеличивает I/O и время удержания соединения. Дольше живущий запрос удерживает ресурс, а новые запросы создают очередь.
5. OOM-killer или лимит cgroup
Когда система больше не может удовлетворить запрос на память, возможны два разных сценария. На уровне хоста Linux может выбрать процесс для завершения. В контейнере лимит cgroup может сработать раньше: контейнер получит событие нехватки памяти, даже если на физической машине ещё есть свободный объём.
Это важное различие при диагностике. Перезапуск приложения после OOM не устраняет причину: он лишь временно возвращает базовый расход памяти. Нужно выяснить, рос ли один процесс, увеличивалось ли число воркеров, был ли пик соединений или память забрали соседние сервисы.
Порядок отказа зависит от архитектуры
Для одной и той же машины с 4 ГБ сценарии будут разными. Сравнивать нужно не только размер приложения, но и место базы, способ запуска и характер нагрузки.
| Схема | Что обычно ограничивает систему | Цена ошибки |
|---|---|---|
| Приложение и PostgreSQL на одной VM | Конкуренция воркеров, базы и кеша ОС | Один всплеск нагрузки ухудшает сразу веб и данные |
| Приложение в cgroup, база отдельно | Лимит памяти приложения или число его воркеров | Контейнер может перезапускаться при живой базе |
| Один процесс с большим heap | Рост heap и паузы сборщика мусора | Задержки растут раньше, чем процесс будет убит |
| Много небольших воркеров | Повторяющийся базовый расход каждого воркера | Новые процессы не помещаются в бюджет |
| Очередь фоновых задач на той же VM | Параллельные задачи и накопленные результаты | Фоновая работа вытесняет пользовательские запросы |
Если база критична для пользовательского запроса, её стоит отделять от экспериментальных воркеров и задач. Если вынести базу нельзя, задайте для сервисов явные лимиты cgroup и оставьте место для ОС. Точное значение лимита выбирайте по измерениям, а не по доле от 4 ГБ.
Как измерить реальный предел
Сначала зафиксируйте конфигурацию: объём RAM, версию ядра, cgroup v1 или v2, версии рантайма и PostgreSQL, число воркеров, настройки пула соединений. Без этого два одинаковых теста «на 4 ГБ» могут проверять разные системы.
- Снимите базовую линию. Наблюдайте память после запуска без трафика и после прогрева кеша. Запишите RSS процессов, потребление cgroup, swap, page cache и число соединений.
- Разделите нагрузку. Отдельно проверьте чтение, запись, тяжёлые отчёты, загрузку файлов и фоновые задачи. Средняя нагрузка скрывает короткие пики.
- Повышайте параллельность ступенчато. На каждом уровне фиксируйте p95 и p99 задержки, ошибки, длину очереди, OOM-события и объём временных файлов PostgreSQL.
- Повторите тест после прогрева. Холодный кеш и прогретый кеш дают разные результаты. В проде важны оба сценария: после рестарта и через несколько часов работы.
- Проверьте восстановление. Зафиксируйте, сколько занимает перезапуск воркера или контейнера и не приводит ли он к каскадному росту нагрузки на базу.
Замер «свободной памяти раз в минуту» недостаточен. Пик, который длится несколько секунд, может убить процесс и исчезнуть до записи метрики. Нужны события OOM, метрики cgroup и временные ряды с интервалом, подходящим для вашего трафика.
Граничные случаи и подводные камни
- Swap не превращает 4 ГБ в 8 ГБ. Он может смягчить короткий пик, но активное вытеснение страниц увеличивает задержки. Смотрите не только на наличие swap, но и на фактическое давление памяти и I/O.
- Лимит контейнера не равен лимиту процесса. Один воркер может выглядеть умеренно по RSS, пока вся cgroup уже занята кешем, дочерними процессами и буферами.
- Утечка и рост кеша выглядят по-разному. Утечка обычно сохраняет занятые страницы после снижения нагрузки. Кеш может уменьшиться, когда памяти потребует другой процесс.
- Падение базы может быть вторичным. PostgreSQL иногда оказывается жертвой нехватки памяти, хотя источник — бесконтрольный параллелизм приложения или фоновые задачи.
- Увеличение таймаутов не лечит дефицит. Оно дольше удерживает соединения и может увеличить очередь, а вместе с ней — и потребление памяти.
Инвалидация кеша, выбор индексов и настройка конкретного рантайма — отдельные темы. Здесь важен порядок диагностики: сначала общий бюджет и границы процессов, затем отдельные запросы и настройки.
Что делать дальше
Составьте карту памяти для каждого сервиса и укажите для него базовый расход, пик, лимит cgroup и допустимое число параллельных операций. После этого поставьте алерты не только на процент занятой RAM, но и на OOM, swap-in, p99 задержки, длину очередей и временные файлы базы.
Следующий практический шаг — нагрузочный тест с теми же лимитами, что и в проде. Если система достигает p99 или ошибок раньше, чем память заканчивается, проблема может быть в CPU, диске, пуле соединений или очереди. Если же первым приходит OOM, уменьшайте параллелизм и разделяйте сервисы до покупки более крупной машины.
Контент-конвейер: Из одной идеи — текст, изображение, озвучка и ролик. Один заказ вместо четырёх.
Спросить за 60 ₽Источники: Control Group v2 — документация ядра Linux, PostgreSQL 16 — Resource Consumption
Частые вопросы
Хватит ли 4 ГБ для сайта и PostgreSQL на одной машине?
Что обычно происходит первым: приложение или база?
Можно ли считать swap запасом оперативной памяти?
Что будет, если я не успею настроить лимиты до запуска?
У меня другая версия Linux или PostgreSQL. Можно использовать этот разбор?
Почему приложение не падает, но запросы начинают отвечать медленно?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.