Выберите продукт

PostgreSQL could not resize shared memory segment: как исправить /dev/shm в Docker и systemd на Linux

Ошибка PostgreSQL could not resize shared memory segment обычно связана не с самой базой, а с нехваткой shared memory: слишком маленьким /dev/shm в Docker, ограничениями tmpfs или неудачными параметрами systemd и cgroup. Разберём пошаговую диагностику и безопасные способы исправления.
PostgreSQL could not resize shared memory segment: как исправить /dev/shm в Docker и systemd на Linux

Ошибка could not resize shared memory segment у PostgreSQL на Linux выглядит тревожно, но в большинстве случаев причина вполне приземлённая: процессу не хватает общей памяти, обычно в /dev/shm или в связанном с ним механизме tmpfs. Особенно часто это проявляется в Docker-контейнерах, где shared memory по умолчанию заметно меньше, чем ожидает база под реальной нагрузкой.

Типичный сценарий такой: PostgreSQL нормально стартует, проходит инициализацию, а затем под нагрузкой, во время тяжёлого запроса, сортировки, параллельного выполнения или обслуживания нескольких активных сессий подряд начинает падать с сообщением о невозможности увеличить сегмент shared memory. Иногда это всплывает сразу после увеличения shared_buffers, work_mem или после переезда базы в контейнер.

Сложность в том, что одно и то же сообщение может указывать на разные источники проблемы: маленький /dev/shm внутри контейнера, отдельный mount tmpfs от systemd, жёсткие memory-лимиты cgroup, нехватку RAM с учётом кэша и IPC или неудачное сочетание параметров PostgreSQL с параллелизмом.

Поэтому правильный порядок здесь важнее самого набора команд: сначала локализуем лимит, потом проверяем Docker и systemd, и только после этого трогаем параметры PostgreSQL. Частая ошибка — сразу уменьшать shared_buffers, хотя реальная проблема может быть вовсе не в нём.

Практическое правило простое: если PostgreSQL работает в контейнере и в ошибке есть намёк на /dev/shm, первым подозреваемым должен быть размер shared memory в Docker. Если база запущена как systemd-сервис с изоляцией, проверяем namespace, tmpfs и memory-ограничения. Если это обычная система без контейнера, смотрим фактический mount /dev/shm, доступную память и реальные параметры экземпляра.

Что означает ошибка PostgreSQL shared memory

Сообщение PostgreSQL could not resize shared memory segment означает, что сервер попытался увеличить сегмент общей памяти, но ОС отказала. В тексте ошибки часто виден путь вида /PostgreSQL.123456789 и системное пояснение вроде No space left on device или Cannot allocate memory. На Linux это нередко связано с POSIX shared memory, использующей /dev/shm.

Важно: это не всегда означает, что на сервере закончилась вся оперативная память. Очень часто проблема уже и локальнее — например, конкретный tmpfs ограничен 64 МБ, хотя на хосте свободны гигабайты. Именно поэтому в Docker ошибка может появляться даже на мощной машине.

Отдельный нюанс в том, что PostgreSQL использует shared memory не только для буферного кэша. На картину влияют параллельные запросы, динамическая shared memory, служебные операции, фоновые процессы и расширения. Из-за этого на тестах всё может быть спокойно, а в продакшене проблема проявится резко и неочевидно.

Если в логах фигурирует /dev/shm, почти никогда не стоит начинать с тюнинга SQL. Сначала проверяют инфраструктурный лимит памяти, потом уже конфигурацию PostgreSQL.

Где проблема возникает чаще всего

Docker и Compose

У контейнеров Docker /dev/shm по умолчанию маленький. Для PostgreSQL, особенно при параллельных планах, построении индексов и тяжёлых сортировках, этого запаса часто недостаточно. База может стартовать без проблем, но падать на CREATE INDEX, больших ORDER BY, hash-операциях, аналитических запросах и массовом импорте.

systemd с изоляцией сервиса

Если PostgreSQL запускается не штатным юнитом пакета, а собственным systemd-сервисом с дополнительными параметрами безопасности, могли появиться настройки, меняющие видимость или размер временных файловых систем. Например, отдельные namespace, приватный /tmp, собственные tmpfs-монтирования или ограничение памяти.

Ограничения памяти через cgroup

Даже если /dev/shm формально выглядит достаточно большим, контейнер или сервис может быть ограничен по памяти. Тогда PostgreSQL пытается расширить shared memory, но фактически упирается в cgroup-лимит. Это особенно заметно в Docker с ограничением RAM или в systemd при использовании MemoryMax.

Неудачные настройки PostgreSQL

Слишком агрессивные значения shared_buffers, завышенный work_mem, большое число соединений и активный параллелизм сами по себе не всегда вызывают ошибку, но создают условия, при которых маленький /dev/shm становится критичным.

Если вам нужна более предсказуемая среда для базы и системных сервисов, такую нагрузку обычно удобнее размещать на отдельном VDS, где проще контролировать cgroup-лимиты, mount-параметры и ресурсы контейнеров.

Проверка размера /dev/shm внутри Docker-контейнера

Быстрая диагностика: что проверить первым делом

Начните с логов PostgreSQL. Нас интересует полный текст ошибки, особенно системное пояснение от ОС: No space left on device, Cannot allocate memory и похожие сообщения. По ним проще отличить нехватку места в tmpfs от общего memory pressure.

journalctl -u postgresql -n 100 --no-pager
journalctl -u docker -n 100 --no-pager
docker logs postgres

Дальше проверьте размер и заполнение /dev/shm именно там, где реально запущен PostgreSQL. Не на хосте вообще, а внутри контейнера или в контексте systemd-сервиса.

df -h /dev/shm
mount | grep shm
free -h

Если PostgreSQL работает в контейнере, смотрите внутрь него:

docker exec -it postgres df -h /dev/shm
docker exec -it postgres mount | grep shm
docker inspect postgres --format '{{.HostConfig.ShmSize}}'

Если последняя команда показывает 67108864, это и есть 64 МБ по умолчанию — для PostgreSQL этого часто мало.

После этого проверьте реальные параметры самой базы:

psql -U postgres -c "show shared_buffers;"
psql -U postgres -c "show work_mem;"
psql -U postgres -c "show max_connections;"
psql -U postgres -c "show max_parallel_workers;"
psql -U postgres -c "show dynamic_shared_memory_type;"

Если база работает под systemd, посмотрите, нет ли drop-in-конфигов и нестандартных ограничений:

systemctl cat postgresql
systemctl show postgresql -p MemoryMax -p PrivateTmp -p TemporaryFileSystem -p ProtectSystem

На практике этого уже хватает, чтобы локализовать значительную часть инцидентов. Если у вас контейнерная среда с усиленной изоляцией, полезно также понимать, как разные механизмы изоляции влияют на ресурсы процессов: об этом мы уже писали в материале про изоляцию контейнеров и её практические последствия.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Как исправить проблему в Docker

Если PostgreSQL работает в Docker, самое частое и правильное решение — явно увеличить shared memory для контейнера. То есть не «лечить» базу случайным уменьшением параметров, а дать ей нормальный размер /dev/shm.

Для разового запуска используйте параметр --shm-size:

docker run -d --name postgres --shm-size=1g -e POSTGRES_PASSWORD=secret postgres:16

Для Docker Compose задайте параметр в описании сервиса:

services:
  postgres:
    image: postgres:16
    shm_size: 1gb
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:

Сколько ставить? Для маленьких установок часто хватает 256m или 512m, но если есть аналитические запросы, тяжёлые индексы, параллельные планы или просто активная база, разумнее начинать с 1g и смотреть по фактической нагрузке. Shared memory лучше выделять с запасом, а не впритык.

После изменения параметра контейнер нужно пересоздать. Обычный рестарт не всегда применяет новое значение, если контейнер уже был создан со старой конфигурацией.

docker compose down
docker compose up -d

Если одновременно заданы ограничения памяти контейнера, проверяйте их вместе с shm_size. Бессмысленно выдавать контейнеру /dev/shm на 1 ГБ, если весь контейнер ограничен, например, 512 МБ RAM.

Ещё один частый сценарий: база в контейнере, а мониторинг показывает свободную память на хосте. Это не опровергает проблему, потому что контейнерный /dev/shm — отдельный лимит, и он может закончиться независимо от общей памяти сервера.

Что делать, если PostgreSQL запущен как systemd-сервис

На обычной Linux-системе /dev/shm чаще всего смонтирован как tmpfs размером в долю от RAM. Но в systemd-сервисах ситуацию могут менять ограничения и переопределения. Если вы используете кастомный юнит, обязательно проверьте, не подменяете ли временные файловые системы и не урезаете ли ресурсы сервиса.

Сначала посмотрите текущий mount и размер:

df -h /dev/shm
mount | grep '/dev/shm'

Если размер слишком мал, проверьте, как смонтирован /dev/shm в системе. Временное решение можно применить через remount, но делать это стоит осознанно и в окно обслуживания:

mount -o remount,size=1G /dev/shm

Чтобы изменение переживало перезагрузку, обычно правят запись в /etc/fstab:

tmpfs /dev/shm tmpfs defaults,size=1G 0 0

Если дело именно в systemd-юните, проверьте, не задан ли для сервиса собственный TemporaryFileSystem или жёсткий лимит памяти. Часто проблема появляется после «усиления безопасности» по чужому шаблону, где в сервис без разбора добавили ограничивающие директивы.

systemctl cat postgresql
systemctl show postgresql -p MemoryMax -p TasksMax -p PrivateTmp -p TemporaryFileSystem

Если нашли ограничение через MemoryMax, оцените, достаточно ли его для PostgreSQL с текущими параметрами. Слишком низкий лимит способен ломать работу даже при нормальном размере /dev/shm.

Переопределение через drop-in может выглядеть так:

systemctl edit postgresql
[Service]
MemoryMax=0

После изменения перечитайте конфигурацию и перезапустите сервис:

systemctl daemon-reload
systemctl restart postgresql

Значение 0 здесь означает отсутствие лимита со стороны этой директивы. Но применять его стоит только если вы понимаете общую модель потребления памяти на сервере. Часто лучше задать реалистичный предел, а не снимать ограничение полностью.

Проверка лимитов памяти и tmpfs для systemd-сервиса PostgreSQL

Когда проблема не в /dev/shm, а в настройках PostgreSQL

Бывает и обратная ситуация: вы увеличили shm_size в Docker или размер системного /dev/shm, а ошибка или нестабильность остались. Тогда уже имеет смысл внимательно смотреть на конфигурацию самой базы.

Первый кандидат — shared_buffers. На небольших серверах его нередко выставляют слишком щедро, ориентируясь на усреднённые советы, но забывают про память ОС, файловый кэш, фоновые процессы, соединения и соседние сервисы. Если в контейнере у вас 2 ГБ RAM, а shared_buffers выставлен 1 ГБ, пространства для манёвра остаётся мало.

Второй кандидат — work_mem. Он не резервируется заранее на каждую сессию, но при активной параллельной нагрузке может резко увеличить фактическое потребление памяти. Поэтому большие значения «на всякий случай» — плохая практика. Лучше повышать его точечно для конкретных задач.

Третий фактор — параллелизм. Параметры max_parallel_workers, max_parallel_workers_per_gather и связанная с ними активность могут заметно увеличивать использование dynamic shared memory. Если сбой проявляется только на тяжёлых аналитических запросах, это очень вероятный след.

Как диагностический шаг можно временно уменьшить параллелизм и проверить, исчезает ли ошибка:

psql -U postgres -c "alter system set max_parallel_workers_per_gather = 0;"
psql -U postgres -c "select pg_reload_conf();"

Это не обязательно финальное решение, но полезная проверка. Если после отключения параллельных планов проблема пропала, значит shared memory действительно упиралась в динамические механизмы выполнения запросов.

Практический порядок исправления без лишнего риска

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

  1. Соберите точный текст ошибки из логов PostgreSQL и ОС.

  2. Проверьте размер /dev/shm в том окружении, где реально работает процесс базы.

  3. Если это Docker — увеличьте shm_size и пересоздайте контейнер.

  4. Если это systemd — проверьте MemoryMax, TemporaryFileSystem и фактический mount /dev/shm.

  5. Оцените соотношение RAM сервера, лимитов cgroup и параметров PostgreSQL.

  6. Только после этого корректируйте shared_buffers, work_mem и параллелизм.

Такой порядок почти всегда экономит время и уменьшает риск «починить» симптом, но оставить настоящую причину. Если вы часто гоняете обновления конфигов, миграции и проверку восстановления, полезно иметь отдельный контур для экспериментов — например, через подход с песочницей для тестов бэкапов и изменений.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Какие значения считать разумными

Универсальной цифры для /dev/shm нет, но есть практичные ориентиры. Для тестового контейнера PostgreSQL без тяжёлых запросов безопасный минимум — 256m. Для небольшой production-нагрузки чаще разумно сразу ставить 512m или 1g. Для аналитики, ETL, построения индексов и многопоточной обработки этого уже может быть мало.

С параметром shared_buffers тоже не стоит гнаться за максимумом. На небольших серверах лучше консервативная и предсказуемая конфигурация, чем агрессивный тюнинг по чужому шаблону. PostgreSQL хорошо использует и файловый кэш ОС, поэтому слишком большой shared_buffers не всегда даёт выигрыш.

Если база живёт в Docker, думайте о памяти в трёх слоях: RAM хоста, лимит контейнера и размер /dev/shm. Узкое место может быть в любом из них.

Как убедиться, что проблема устранена

После изменения конфигурации не стоит ограничиваться фактом, что ошибка исчезла. Важно убедиться, что появился запас, а не просто немного отодвинулся порог сбоя.

  • Проверьте размер и заполнение /dev/shm после рестарта.

  • Убедитесь, что у контейнера или systemd-сервиса нет неожиданного memory-лимита.

  • Посмотрите логи PostgreSQL под типовой и пиковой нагрузкой.

  • Прогоните тяжёлые запросы, индексацию и batch-задачи.

  • Убедитесь, что после увеличения лимитов не начались OOM-события по другой причине.

Если есть тестовый стенд, воспроизведите сценарий с тем же профилем запросов. Если отдельного стенда нет, хотя бы прогоните типовые операции: создание индекса, массовый импорт, большой ORDER BY, hash join и параллельные выборки. Именно на них дефицит shared memory проявляется чаще всего.

Частые ошибки администраторов

Первая ошибка — смотреть df -h /dev/shm на хосте и считать, что этого достаточно. Для контейнеров такая проверка почти бесполезна, если вы не посмотрели то же самое внутри контейнера.

Вторая — увеличивать только shared_buffers после миграции на более мощный сервер и забывать, что в Docker остался дефолтный shm_size. В итоге конфигурация PostgreSQL стала тяжелее, а инфраструктурный лимит — нет.

Третья — бездумно задавать огромный work_mem. На одиночных запросах всё выглядит красиво, а под многопользовательской нагрузкой память начинает расходоваться лавинообразно.

Четвёртая — копировать жёстко ограничивающие настройки systemd из гайдов по hardening без понимания, как они влияют на базы данных. PostgreSQL не любит, когда ему внезапно меняют модель доступа к временным и shared-ресурсам.

Итог

Ошибка could not resize shared memory segment почти всегда указывает не на «сломанный PostgreSQL», а на нехватку shared memory в конкретной среде выполнения. На Linux это чаще всего /dev/shm, в Docker — слишком маленький shm_size, а в systemd — неудачные tmpfs или memory-ограничения.

Надёжный путь решения такой: сначала проверить, какой именно /dev/shm видит процесс, затем исключить лимиты Docker и systemd, после этого сверить конфигурацию PostgreSQL с реальным объёмом памяти. В большинстве случаев проблема устраняется быстро, если не перепрыгивать этапы диагностики.

Если кратко: увидели could not resize shared memory segment — сначала идите проверять /dev/shm, а не гадать на параметрах SQL. В таких инцидентах инфраструктура обычно объясняет поведение базы лучше любой теории.

Поделиться статьей

Вам будет интересно

GRUB rescue: no such partition в Debian и Ubuntu — как восстановить загрузчик, UUID и initramfs OpenAI Статья написана AI (GPT 5)

GRUB rescue: no such partition в Debian и Ubuntu — как восстановить загрузчик, UUID и initramfs

Ошибка GRUB rescue с сообщением no such partition в Debian или Ubuntu обычно появляется после смены UUID, переноса диска, правки р ...
Linux: как исправить server gave HTTP response to HTTPS client в reverse proxy и health checks OpenAI Статья написана AI (GPT 5)

Linux: как исправить server gave HTTP response to HTTPS client в reverse proxy и health checks

Ошибка server gave HTTP response to HTTPS client почти всегда означает путаницу со схемой трафика между клиентом, reverse proxy, б ...
Fail2ban с nftables и journald backend на Debian и Ubuntu OpenAI Статья написана AI (GPT 5)

Fail2ban с nftables и journald backend на Debian и Ubuntu

Показываю, как настроить Fail2ban на Debian и Ubuntu с backend journald и блокировками через nftables. Разберём рабочий jail.local ...