Главная » Веб-серверы и PHP » Apache: No space left on device: Couldn’t create accept lock — нехватка семафоров

Apache: No space left on device: Couldn’t create accept lock — нехватка семафоров

Apache не запускается с ошибкой No space left on device, хотя df -h показывает свободное место. Обычно диск тут ни при чём. Код ошибки 28 (ENOSPC) ядро возвращает и тогда, когда кончились семафоры System V. Apache использует их как мьютексы между своими процессами. Если Apache падал и не успел их удалить, «осиротевшие» семафоры копятся, пока ядро не откажет в новых.

Самое частое решение: остановить Apache, найти командой ipcs -s семафоры пользователя веб-сервера, удалить их командой ipcrm и запустить Apache снова. Чтобы проблема не вернулась, переводим Apache на мьютексы, которые не текут, директивой Mutex, и ищем, почему Apache падает. Повышать лимиты в kernel.sem на современных ядрах обычно не нужно.

Статья написана по двум старым заметкам 2012–2017 годов про CentOS 5/6 и Apache 2.2 и переработана для Apache 2.4 на Debian 12 и 13, Ubuntu 24.04 и AlmaLinux / Rocky Linux 9 и 10.

Как выглядит ошибка

В Apache 2.2 сообщение было таким:

[emerg] (28)No space left on device: Couldn't create accept lock (/etc/httpd/logs/accept.lock.12345)

В Apache 2.4 мьютексы переписали, и текст другой. В названии указано, какой мьютекс не удалось создать:

[core:emerg] [pid 12345] (28)No space left on device: AH00023: Couldn't create the mpm-accept mutex
[core:emerg] [pid 12345] (28)No space left on device: AH00023: Couldn't create the ssl-cache mutex

Иногда в журнале нет ничего полезного, только Configuration Failed. Так было в одном из исходных случаев автора: проверка синтаксиса проходила, режим отладки ничего не давал. Причину показал strace:

strace -f -o /tmp/trace.txt /usr/sbin/httpd -DFOREGROUND
grep ENOSPC /tmp/trace.txt

Примерно так выглядела нужная строка:

semget(IPC_PRIVATE, 1, IPC_CREAT|0600) = -1 ENOSPC (No space left on device)

Системный вызов semget создаёт семафор System V. ENOSPC от него означает «превышен лимит семафоров», а не «нет места на диске». На Debian и Ubuntu бинарник называется /usr/sbin/apache2, и запускать его напрямую лучше через apache2ctl, чтобы подхватились переменные из /etc/apache2/envvars.

Где смотреть журналы

ЧтоDebian, UbuntuAlmaLinux, Rocky
Сервисapache2.servicehttpd.service
Журнал ошибок/var/log/apache2/error.log/var/log/httpd/error_log
Журнал systemdjournalctl -u apache2 -n 50journalctl -u httpd -n 50
Проверка конфигурацииapache2ctl configtestapachectl configtest
Каталог lock-файлов/var/lock/apache2 (APACHE_LOCK_DIR)/run/httpd

Старое сообщение CentOS 6 httpd dead but subsys locked в системах с systemd не встречается. Теперь сервис просто переходит в состояние failed, а причину видно в systemctl status и журнале.

Шаг 1. Убедиться, что дело не в диске

Ошибка 28 бывает и настоящей. Прежде чем трогать семафоры, исключите очевидное:

df -h / /var /run /dev/shm
df -i / /var /run

Обратите внимание на df -i. Кончившиеся inode тоже дают No space left on device при свободных гигабайтах. Чаще всего их съедают миллионы мелких файлов сессий PHP или кэша. Если мьютексы Apache работают через файлы, они создаются в каталоге lock-файлов, и переполненный /run (это tmpfs в памяти) даст ту же ошибку. POSIX-семафоры живут в /dev/shm, его заполнение тоже проявится как ENOSPC.

Шаг 2. Посмотреть семафоры

ipcs -s

Вывод примерно такой:

------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x00000000 32768      www-data   600        1
0x00000000 32769      www-data   600        1
0x00000000 32770      www-data   600        1
...

Владелец — пользователь, от которого работает Apache: www-data на Debian и Ubuntu, apache на AlmaLinux. Посчитать семафоры по владельцам:

ipcs -s | awk 'NR>3 && NF {print $3}' | sort | uniq -c | sort -rn

И сравнить с лимитами ядра:

ipcs -ls
sysctl kernel.sem

Параметр kernel.sem — это четыре числа: SEMMSL (семафоров в одном наборе), SEMMNS (всего семафоров в системе), SEMOPM (операций за один вызов) и SEMMNI (наборов в системе). Apache на каждый мьютекс создаёт один набор, поэтому упирается обычно в последнее число.

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

Шаг 3. Удалить осиротевшие семафоры

Сначала полностью остановите Apache. Удалять семафоры работающего сервера нельзя: процессы, которые их используют, начнут сбоить.

# Debian, Ubuntu
systemctl stop apache2
pgrep -a apache2      # должно быть пусто

# AlmaLinux, Rocky
systemctl stop httpd
pgrep -a httpd

Удаляем только семафоры пользователя веб-сервера. Для AlmaLinux замените www-data на apache:

ipcs -s | awk '$3 == "www-data" {print $2}' | xargs -r -n1 ipcrm -s

Запускаем и проверяем:

systemctl start apache2
systemctl status apache2
ipcs -s

В интернете и в старой версии этой статьи встречается цикл, который удаляет вообще все семафоры в системе:

for id in `ipcs -s | awk '{print $2}'`; do ipcrm -s $id; done

Так делать не стоит. Семафоры System V используют и другие программы: СУБД, сервер приложений, сторонние демоны. Удалив их семафоры, вы сломаете уже работающие сервисы. То же относится к ipcrm --all=sem. Фильтруйте по владельцу.

Шаг 4. Директива Mutex: чтобы семафоры не текли

В Apache 2.4 механизм межпроцессных блокировок задаёт директива Mutex. По умолчанию (Mutex default) механизм выбирает библиотека APR при сборке. Узнать, какой выбран в вашей сборке:

apache2ctl -V | grep SERIALIZE    # Debian, Ubuntu
httpd -V | grep SERIALIZE         # AlmaLinux, Rocky

Например, Apache 2.4.58 в Ubuntu 24.04 выводит такие строки:

 -D APR_USE_PROC_PTHREAD_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT

Это значит, что по умолчанию используются мьютексы pthread в разделяемой памяти, а не семафоры System V. Если же вывод содержит APR_USE_SYSVSEM_SERIALIZE, или в конфиге явно стоит Mutex sysvsem, утечка семафоров возможна. Документация Apache прямо предупреждает: семафоры SysV «текут», если процесс падает, не удалив их.

Явный Mutex sysvsem часто приезжает со старыми конфигами при переносе сайтов с CentOS 6. Найдите его:

grep -rn -i '^\s*Mutex' /etc/apache2/    # Debian, Ubuntu
grep -rn -i '^\s*Mutex' /etc/httpd/      # AlmaLinux, Rocky

Директивы Apache 2.2 AcceptMutex, LockFile, RewriteLock и SSLMutex в 2.4 удалены, их заменяет Mutex. Если такие строки остались в конфиге, Apache 2.4 не запустится с ошибкой о неизвестной директиве.

Варианты, которые не оставляют мусора в таблице семафоров:

МеханизмЧто этоКогда подходит
defaultВыбор APR; в современных сборках для Linux обычно pthreadПочти всегда. Лучше просто убрать явный Mutex sysvsem
pthreadМьютексы POSIX в разделяемой памятиLinux умеет восстанавливать такой мьютекс после падения процесса
file:/путьБлокировка через lock-файл (fcntl или flock)Надёжно и наглядно; каталог только на локальном диске, не на NFS
posixsemСемафоры POSIX в /dev/shmРаботает, но по документации может подвесить сервер, если упал процесс, державший мьютекс
sysvsemСемафоры System VПричина этой ошибки. Использовать только при явной необходимости

На Debian и Ubuntu в /etc/apache2/apache2.conf уже есть закомментированная строка с файловым вариантом. Её достаточно раскомментировать:

Mutex file:${APACHE_LOCK_DIR} default

На AlmaLinux добавьте файл /etc/httpd/conf.d/mutex.conf:

Mutex file:/run/httpd default

Не кладите lock-файлы в /tmp или /var/tmp. Документация Apache предупреждает: любой пользователь может заранее создать там файл с тем же именем и не дать серверу запуститься. Есть и вторая причина. У сервиса Apache в systemd включён PrivateTmp=true и на Debian, и на AlmaLinux. Сервис видит свой собственный /tmp, а вы из консоли — общий. Если запускать Apache то через systemd, то вручную, lock-файлы окажутся в разных местах, а ошибки будет трудно понять.

Проверяем и перезапускаем:

apache2ctl configtest && systemctl restart apache2   # Debian, Ubuntu
apachectl configtest && systemctl restart httpd      # AlmaLinux, Rocky

После перезапуска в каталоге lock-файлов появятся файлы вида mpm-accept.12345, а ipcs -s перестанет пополняться наборами пользователя Apache.

Почему семафоры остаются: ищем причину падений

Apache удаляет свои семафоры при нормальной остановке. Утечка — признак того, что главный процесс завершается аварийно. Мьютекс можно сменить, но причину падений нужно найти:

  • OOM killer. Когда кончается память, ядро убивает процессы, иногда и главный процесс Apache. Проверка: journalctl -k | grep -i -E 'out of memory|killed process'.
  • Падения модулей. Segmentation fault в журнале ошибок Apache. Классические виновники — mod_php с проблемным расширением, сторонние модули, собранные под другую версию. Лечится обновлением модуля или переходом с mod_php на PHP-FPM.
  • Жёсткая остановка. kill -9 по процессам Apache из скриптов «перезапуска», которые писали для старых серверов. Используйте systemctl restart или apachectl graceful.
  • Сторонние модули со своими семафорами. Не все модули используют общий механизм Apache. Если после смены Mutex семафоры продолжают копиться, отключайте подозрительные модули по одному и смотрите на ipcs -s.

Переход с mod_php на PHP-FPM убирает сразу две проблемы: Apache работает в режиме event, а PHP падает в своих процессах, не задевая веб-сервер. Как это настроить, описано в статье Несколько версий PHP и PHP-FPM на одном сервере.

Нужно ли повышать kernel.sem

В исходной статье лимиты поднимали так:

kernel.msgmni = 1024
kernel.sem = 250 256000 32 10241

Для ядер CentOS 5 и 6 это имело смысл: по умолчанию там было всего 128 наборов семафоров. С ядра 3.19 значения по умолчанию сильно выросли. На Debian 12 и 13, Ubuntu 24.04 и AlmaLinux 9 и 10 обычно стоит:

$ sysctl kernel.sem
kernel.sem = 32000	1024000000	500	32000

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

Если поднять лимит всё же нужно (например, этого требует документация другой программы), делайте это отдельным файлом в /etc/sysctl.d, а не правкой /etc/sysctl.conf:

cat > /etc/sysctl.d/90-sem.conf <<'EOF'
kernel.sem = 32000 1024000000 500 32000
EOF
sysctl --system
sysctl kernel.sem

В kernel.sem задаются все четыре числа сразу, поэтому сначала посмотрите текущие значения и меняйте только нужное.

Apache в контейнере

Семафоры System V принадлежат пространству имён IPC. В контейнерах LXC (в том числе в Proxmox VE) и Docker у контейнера своя таблица семафоров. Команда ipcs -s на хосте не покажет семафоры контейнера, смотреть нужно внутри. Лимиты kernel.sem тоже свои у каждого пространства имён. В старых контейнерах OpenVZ лимиты задавал хост, и ошибка часто приходила именно оттуда.

На хосте с systemd 248 и новее можно дать сервису отдельное пространство имён IPC параметром PrivateIPC=yes в override-файле (systemctl edit apache2). Тогда при остановке сервиса его семафоры исчезают вместе с пространством имён. Но и в ipcs -s с хоста их видно не будет, а модули, которые общаются с другими процессами через IPC, перестанут их видеть. Это дополнительная мера, а не замена правильной директиве Mutex.

Симптомы, причины и решения

СимптомПричинаРешение
(28)No space left on device: AH00023: Couldn't create the ... mutex, место на диске естьКончились наборы семафоров System VОстановить Apache, удалить семафоры его пользователя через ipcrm, сменить Mutex
То же, ipcs -s почти пустФайловый мьютекс, переполнен /run или кончились inode; переполнен /dev/shm при posixsemdf -h, df -i, освободить место
Только Configuration Failed в журналеПричина скрыта, часто те же семафорыstrace -f, искать ENOSPC
Семафоры копятся снова через дни или неделиАварийное завершение Apache: OOM, segfault модулей, kill -9Найти причину падений в журналах, перейти на PHP-FPM
Apache 2.4 не стартует после переноса конфига с 2.2Директивы AcceptMutex, LockFile, RewriteLock, SSLMutexЗаменить на Mutex
Ошибка только внутри контейнераЛимиты IPC пространства имён контейнераЧистить и смотреть ipcs внутри контейнера

Частые вопросы

Почему ошибка говорит про место на диске, если дело в семафорах?

Ядро Linux возвращает один и тот же код ошибки ENOSPC в разных ситуациях. Для semget он означает, что превышен лимит наборов семафоров или семафоров в системе. Apache просто печатает стандартный текст этого кода — No space left on device. Поэтому df ничего не показывает.

Безопасно ли удалять семафоры командой ipcrm?

Безопасно, если Apache остановлен и вы удаляете только семафоры его пользователя (www-data или apache). Опасно удалять все семафоры подряд: среди них могут быть семафоры работающих СУБД и других сервисов. Удалённый семафор восстановить нельзя, программа, которая его использовала, начнёт сбоить до перезапуска.

Помогает ли перезагрузка сервера?

Да, семафоры System V живут в памяти ядра и исчезают при перезагрузке. Но это то же самое, что удалить их вручную, только с простоем всех сервисов. И если Apache продолжит падать, через какое-то время ошибка вернётся. Перезагрузка лечит симптом, директива Mutex и поиск причины падений — проблему.

Встречается ли эта ошибка на Nginx?

Практически нет. Nginx не использует семафоры System V для синхронизации своих процессов. Если вы видите No space left on device у Nginx, ищите настоящую нехватку места или inode: под кэш, временные файлы или журналы.

Нужно ли отключать SELinux, если Apache не стартует?

Нет. В исходном случае автора setenforce 0 проверяли «на всякий случай», и он ничего не изменил: SELinux к семафорам отношения не имеет. Отключать SELinux целиком ради диагностики не нужно. Если подозреваете его, посмотрите отказы командой ausearch -m avc -ts recent на AlmaLinux и исправьте конкретное правило или контекст файлов.

Какой механизм Mutex выбрать на новом сервере?

Ничего не выбирать и оставить Mutex default: в современных сборках Apache для Linux это обычно pthread, и семафоры System V не используются. Проверьте вывод apache2ctl -V или httpd -V. Если там APR_USE_SYSVSEM_SERIALIZE или вы уже столкнулись с утечкой, задайте Mutex file: с каталогом на локальном диске.